-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) Β· 61.2 KB
/
content.json
1
{"pages":[{"title":"","text":"","link":"/404.html"},{"title":"Archives","text":"","link":"/archive/index.html"},{"title":"About","text":"ε
ζε₯½ε₯εΏθδΈε»ε―¦θΈοΌηζΌθͺι‘ζΎζ£ζεζ©ζ ε₯ηΊθͺε·±η«ε°θͺιοΌJust Do ItοΌοΌ","link":"/about/index.html"},{"title":"Tags","text":"","link":"/tags/index.html"}],"posts":[{"title":"Facade Pattern","text":"λμμΈ ν¨ν΄ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ° μ€κ³μμ μμ£Ό λ°μνλ λ¬Έμ λ€μ νΌνκΈ° μν΄ μ¬μ©λλ ν¨ν΄ λ€λ§, μκ³ λ¦¬μ¦μ΄ μλλΌ μν©μ λ°λΌ μμ£Ό μ°μ΄λ μ€κ³ λ°©λ²μ μ 리ν μ½λ© λ°©λ²λ‘ μ΄λ©° λͺ¨λ μν©μ ν΄κ²°μ±
μ μλλ€. μ€μν κ²μ λμμΈ ν¨ν΄μ μ½λ§€μ΄λ κ²μ΄ μλλΌ κ·Έ ν¨ν΄μ΄ μ ν¨μ¨μ μΈ λ°©μμΈμ§λ₯Ό μ΄ν΄νμ¬μΌ νλ€. νμ¬λ(Facade) ν¨ν΄ 볡μ‘ν μλΈμμ€ν
μ μΈν°νμ΄μ€ κ°μΈ κ°λ¨νκ² λ§λλ ν¨ν΄μ΄λ©° 3μ API(Third Party API)κ°μ μΈλΆ λΌμ΄λΈλ¬λ¦¬λ₯Ό μΆμν νλλ°λ μ¬μ©λ©λλ€. νλ‘μ νΈ μ 체μ νΉμ ν μ½λκ° λΆλΆμ μΌλ‘ λΆν¬λμ΄ μμ κ²½μ° μ μ§λ³΄μμ νμνλ€. 123456789101112package ThirdPartyAPI;public class DatabaseClient { public DatabaseClient () { } public void find(final String table, final String primaryKey, final Integer maxRetry) { // Database Request to the DB Server }} 12345678910111213import ThirdPartyAPI.DatabaseClient;public class ItemService {private final DatabaseClient databaseClient;public ItemService() {databaseClient = new DatabaseClient();}public void find(final String primaryKey) {databaseClient.find(\"Item\", primaryKey, 3);}} DatabaseClient κ° version Updateλμ΄ find ν¨μμ 맀κ°λ³μκ° λ¬λΌμ§ κ²½μ°, DatabaseClientλ₯Ό κ°μΈκ³ μλ ItemService μ νΈμΆλΆλΆλ§ λ³κ²½ν΄μ£Όλ©΄ λλ€. 123456789101112public class ItemService { private final DatabaseClient databaseClient; public ItemService() { databaseClient = new DatabaseClient(); } public void find(final String primaryKey) { DatabaseOption databaseOption = new DatabaseOption.Builder(\"Item\") .withPrimaryKey(primaryKey).withMaxRetry(3).build(); databaseClient.find(databaseOption); } λ§μ½ νμ¬λ ν¨ν΄μ΄ μλμλ€λ©΄? μ½λλ₯Ό κ³ μΉ κ³³μ μ λν
μ€νΈλ₯Ό μ λΆ λ€μ ν΄μΌ νλ€. κ·Έλ¦¬κ³ μ λν
μ€νΈλ₯Ό λͺ¨λ κ³ μΉ ν μΈν
κ·Έλ μ΄μ
ν
μ€νΈλ₯Ό νμ΄μΌ ν κ²μ΄λ€. ν
μ€ν
μκ°μ΄ κΈΈλ€λ©΄ ν¬κ²μ΄νΈ μ€ν μ°Έκ³ λμμΈ ν¨ν΄μ΄λ λ무μν€_λμμΈν¨ν΄ itertools γ
γ
γ
γ· - μ΄ν°λ μ΄ν°, μ λλ μ΄ν° python 2.2 doc λμμΈ ν¨ν΄ - μ€λ¬΄νΈ νμ¬λ ν¨ν΄ - νμ
νμ¬λ ν¨ν΄ - Logbridge","link":"/2020/02/01/Design_Pattern/Facade_Pattern/"},{"title":"Prototype Pattern","text":"νλ‘ν νμ
λμμΈ ν¨ν΄ μνμ΄ λλ μΈμ€ν΄μ€λ₯Ό μ¬μ©νμ¬ μμ±ν κ°μ²΄μ μ’
λ₯λ₯Ό λͺ
μνκ³ , μ΄λ κ² λ§λ 견본μ 볡μ¬ν΄μ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±ν©λλ€. μμ±ν κ°μ²΄λ€μ νμ
μ΄ νλ‘ν νμ
μΈ μΈμ€ν΄μ€λ‘ λΆν° κ²°μ λλλ‘ νλ©°, μΈμ€ν΄μ€λ μ κ°μ²΄λ₯Ό λ§λ€κΈ° μν΄ μμ μ 볡μ (clone)νλ ν¨ν΄μ΄λ©° κ°μ²΄λ₯Ό μμ±(create)νλ κ³ μ μ λΉμ©μ΄ λΆκ°νΌνκ² λ§€μ° ν΄ λ, μ΄ λΉμ©μ μ€μΌ μ μμ΅λλ€. [μν€λ°±κ³Ό] ꡬν μμ±λ κ°μ²΄λ₯Ό 볡μ¬νμ¬ κ΅¬νλ©λλ€. 1234567891011121314151617181920212223242526from copy import deepcopyclass Point(object): def __init__(self, x, y): self.x = x self.y = y def move_point(self, x, y): self.x += x self.y += y def display_point(self): print(f'{self.x}, {self.y}') def clone(self): obj = deepcopy(self) return objif __name__ == '__main__': p1 = Point(1,2) p1.display_point() p2 = p1.clone() p2.move_point(2,3) p2.display_point() # 2 3 p1.display_point() # 1 2 copy.deepcopy(self), κΉμ λ³΅μ¬ or copy.copy(self), μμ λ³΅μ¬ λ₯Ό ν΅ν΄ κ°μ²΄λ₯Ό 볡μ¬νμ¬ κ΅¬νν μ μμ΅λλ€. μΆκ°λ‘ νμ΄μ¬μ λ§€μ§ λ©μλ(__init__, __call__)λ‘ νμ©νμ¬ κ°μ²΄ μμ±μ 리μμ€λ₯Ό μ μ½ν μ μμ΅λλ€. 12345678Class Handler: def __init__(self): # λͺ¨λΈ Load λ° νμ΅ self.model = Predictor() self.model.load_weights() def __call__(self, req): # req κ° λͺ¨λΈ μ μ© return self.model(req.input) ν λΉ(=) vs κΉμ λ³΅μ¬ vs μμ λ³΅μ¬ ν΄λμ€λ₯Ό ν λΉνλ©΄ λλλ° κ΅³μ΄ κΉμ 볡μ¬λ₯Ό ν΄μΌνλ μ΄μ κ° μ‘΄μ¬ν©λλ€. μλ λ°©μμ μ°¨μ΄ λλ¬ΈμΈλ°μ. λ€μκ³Ό κ°μ κ·Έλ¦ΌμΌλ‘ μλ μ°¨μ΄λ₯Ό νμ
ν μ μμ΅λλ€. ν λΉκ³Ό μμ 볡μ¬μ μ°¨μ΄μ μ κ°μ²΄ μμ±μ μ°¨μ΄μ΄λ©°, κΉμ 볡μ¬μ μμ 볡μ¬μ μ°¨μ΄λ κ°μ κ°λ₯΄ν€λ ν¬μΈν°μ μ°¨μ΄μ
λλ€! μ΄λμ μ¬μ©ν΄μΌ ν κΉμ? μμ μμ λ₯Ό 보μ κ²μ²λΌ νλ‘ν νμ
ν¨ν΄μ μμ μ κ°μ²΄λ₯Ό μμ±(create)νλ κ³ μ μ λΉμ©μ΄ λΆκ°νΌνκ² λ§€μ° ν΄ λ, μ΄ λΉμ©μ μ€μ μ μμ΅λλ€. κ³ μ μ λΉμ©μ΄ 무μμΌκΉμ? μμΈν νμ©μ²λ₯Ό μκΈ°μν΄ μν€ λ°±κ³Όμμ μκ°ν νλ‘ν νμ
μ νμ©μ²λ₯Ό μ€ν¬λ¦½νΈ ν΄μμ΅λλ€. The Prototype design pattern solves problems like: [3] How can objects be created so that which objects to create can be specified at run-time? λ°νμμμ μμ± κ°μ²΄λ₯Ό μ§μ νκ³ μΆμ λ How can dynamically loaded classes be instantiated? μνκ°μ΄ λ³νλ ν΄λμ€λ₯Ό μΈμ€ν΄μ€ννκ³ μΆμ λ μ΄ν΄λ νλλ° μ΄λ€ μν©μ μ μ ν κΉμ?? μ‘°μ¬μ€λ½κ² μμν΄λ΄
λλ€λ§.. λ°μ΄ν° μ μ²λ¦¬ κ³Όμ μμ 볡μ¬λ₯Ό ν΅ν΄ κ³ μ μ λΉμ©μ μ€μλ κΈ°μ΅μ΄ μμ΅λλ€. κ²°λ‘ λΆν° λ§μλ리면 κ³ μ μ λΉμ©μ `μκ°` μ΄λΌκ³ λ³Ό μ μμ΅λλ€. μ½ 2.5GB μ©λμ CSV λ°μ΄ν°λ₯Ό λ°μ΄ν°νλ μμΌλ‘ λΆλ¬μ¬λ 2λΆμ μκ°μ΄ μλΉλμμ§λ§, λ°μ΄ν°νλ μμ 볡μ¬νλ κ²μλ λ°λ‘ λ κ²μ 보μ **λ°νμμμ 무μμ μμ©**μ ν΅ν΄ κ³ μ μ λΉμ©μ΄ μ€μ§ μμλ μκ°λ©λλ€. 12345import numpy as npimport pandas as pdsearch = pd.read_csv('Search.csv')search.head() CLNT_ID SESS_ID KWD_NM SEARCH_CNT 0 5607714 7112876 λΉλ¦¬ν μμ΄ν¬λ¦Ό 6 1 5607714 4090791 ν리λ©λΌ λ§μ€ν¬ν© 3 2 5607714 4090791 μ¬μ±μ²κ²°μ 1 3 5612428 1876482 λͺ
νκ°λ°© 1 4 5612428 658123 콩μμ΄ μμ΄μ€ν¬λ¦Ό 1 12345search2 = search.copy() search = search.drop(\"CLNT_ID\", axis=1)search.head()search2.head() SESS_ID KWD_NM SEARCH_CNT 0 7112876 λΉλ¦¬ν μμ΄ν¬λ¦Ό 6 1 4090791 ν리λ©λΌ λ§μ€ν¬ν© 3 2 4090791 μ¬μ±μ²κ²°μ 1 3 1876482 λͺ
νκ°λ°© 1 4 658123 콩μμ΄ μμ΄μ€ν¬λ¦Ό 1 CLNT_ID SESS_ID KWD_NM SEARCH_CNT 0 5607714 7112876 λΉλ¦¬ν μμ΄ν¬λ¦Ό 6 1 5607714 4090791 ν리λ©λΌ λ§μ€ν¬ν© 3 2 5607714 4090791 μ¬μ±μ²κ²°μ 1 3 5612428 1876482 λͺ
νκ°λ°© 1 4 5612428 658123 콩μμ΄ μμ΄μ€ν¬λ¦Ό 1 Pandas μμ μ 곡νλ COPY() μ°μ°μΌλ‘ deepcopyκ° λ©λλ€. #1 μμ μμ λ°μ΄ν°λ₯Ό λ‘λνλ μκ°μ΄ μμλμ§ λ°λ©΄, = μ°μ°μΌλ‘ κ°μ²΄λ₯Ό 볡μ¬νλ κ²½μ° μκ° μλΉκ° μλμ μΌλ‘ μ μ κ²μ 체κ°ν μ μμ΅λλ€. κ²°λ‘ νλ‘ν νμ
ν¨ν΄μ μ¬μ©νλ μν©μΌλ‘ ν° λ°μ΄ν°λ₯Ό λ‘λν λ μ¬μ©νκΈ° μ ν©ν©λλ€. λΉμ©μ μΈ‘λ©΄μμλ μκ° μμμ ν¬κ² μλ μ μμμΌλ‘ κ°λ°μ±μ λμΌ μ μμ΄ ν¨μ¨μ μ΄λΌ νλ¨λ©λλ€. μ°Έκ³ νλ‘ν νμ
μν€λ°±κ³Ό λ°μ΄ν° μ μ²λ¦¬ κΉνλΈ ν λΉ vs μμ λ³΅μ¬ vs κΉμ 볡μ¬","link":"/2020/03/20/Design_Pattern/Prototype_Pattern/"},{"title":"κΉνλΈ λΈλ‘κ·Έ ꡬμΆκΈ°","text":"Github Blog κ΅¬μΆ κΈ°μ λΈλ‘κ·Έμ©μΌλ‘ κΉνλΈμ ννμ¬ κ΅¬μΆνλ κ³Όμ μμ μκΈ°λ μλ¬μ λν ν΄κ²° λ°©λ²μ μ 리νμμ΅λλ€. μ κ° μ°Έμ‘°νμ¬ λ°λΌν λ§ν¬λ λ€μκ³Ό κ°μΌλ©°, ν
μ€νΈλ Ubuntu16.04 μμ μ§ννμμ΅λλ€. Hexo install μλ¬ ubuntu16.04 μμ Nodejs Version μμ‘΄μ± λ¬Έμ λ‘ μ
λ°μ΄νΈ νμ, NVM μ€μΉ 12345678910$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash$ export NVM_DIR=\"$HOME/.nvm\"$ [ -s \"$NVM_DIR/nvm.sh\" ] && . \"$NVM_DIR/nvm.sh\"$ nvm install 10.0$ nvm use 10.0$ hexo install **Deployer not found: git :: hexo deploy ** 1npm install hexo-deployer-git --save λΈλ‘κ·Έ μ
λ°μ΄νΈνκΈ° 12$ hexo clean$ hexo deploy --generate μ°Έκ³ https://www.holaxprogramming.com/2017/04/16/github-page-and-hexo/ https://simhyejin.github.io/2016/06/24/hexo-themes/ https://cheese10yun.github.io/blog-start/ hexo μ΄μΉ΄λ£¨μ€ λΈλ‘κ·Έ Alley hexo μ΄μΉ΄λ£¨μ€ κ°μ΄λλΌμΈ","link":"/2020/02/16/blog/Github_Blog_ꡬμΆκΈ°/"},{"title":"ν¨μν μΈμ΄ in νμ΄μ¬","text":"ν¨μν νλ‘κ·Έλλ° ν¨μν νλ‘κ·Έλλ°? μν(λ³μμ λ³ννλ κ°)μ **ν¨μ(Evaluating function)**λ‘ λ체νμ¬ μ½λμ κ°κ²°μ±κ³Ό low-level μμ€μ κΈ°λ₯μ μ€κ³ν μ μλ€. μ΄λ¬ν ν¨μ(Evaluating function)λ μν νμκ³Ό μ μ¬νλ©° κ°λ¨ν λμλ₯Ό μ¬μ©νμ¬ μκ³ λ¦¬μ¦μ μ€κ³ν μ μλ€. λν μ½λκ° κ°κ²°ν΄μ§λ λ§νΌ ν¨μ¨μ μ΄λ μμΈν μ μ΄ λ° μ νν κ²°κ³Όλ₯Ό μν΄ μ μ€ν λμμΈμ΄ νμνλ€. νλ‘κ·Έλλ° ν¨λ¬λ€μ λΉκ΅ λͺ
λ Ήν νλ‘κ·Έλλ°: νλ‘κ·Έλλ°μ μνμ μνλ₯Ό λ³κ²½μν€λ ꡬ문μ κ΄μ μμ μ°μ°μ μ€λͺ
νλ λ°©μ μ μ°¨μ§ν₯ νλ‘κ·Έλλ°: μνλμ΄μΌ ν μ°μμ μΈ κ³μ° κ³Όμ μ ν¬ν¨νλ λ°©μ (C, C++) κ°μ²΄μ§ν₯ νλ‘κ·Έλλ°: κ°μ²΄λ€μ μ§ν©μΌλ‘ νλ‘κ·Έλ¨μ μνΈμμ©μ νν (C++, Java, C#) μ μΈν νλ‘κ·Έλλ°: μ΄λ€ λ°©λ²μΌλ‘ ν΄μΌ νλμ§(How)λ₯Ό λνλ΄κΈ°λ³΄λ€ 무μ(What)κ³Ό κ°μμ§λ₯Ό μ€λͺ
νλ λ°©μ ν¨μν νλ‘κ·Έλλ°: μμ ν¨μλ₯Ό μ‘°ν©νκ³ μννΈμ¨μ΄λ₯Ό λ§λλ λ°©μ (ν΄λ‘μ , νμ€μΌ, 리μ€ν) μμ 1λΆν°μ 10κΉμ§μ μ μ μ€ 3μ 5μ λ°°μμ κ°λ€μ ꡬν΄λ³΄μ μ μ°¨ν νλ‘κ·Έλλ° μνλμ΄μΌ ν μ°μμ μΈ κ³μ° κ³Όμ μ νν, λͺ©νμ μν μκ³ λ¦¬μ¦μ μ€μ 12345# μ μ°¨μ νλ‘κ·Έλλ° , for λ¬ΈμΌλ‘ μ κ·Ό m = list()for n in range(1, 10): if n % 3 == 0 or n % 5 == 0 : m.append(n) ν¨μν νλ‘κ·Έλλ° μμ ν¨μλ₯Ό μ‘°ν©ν¨, λͺ©νμ μ€μ μΌλ ¨μ μ«μμ ν©, κ°λ¨ν ν
μ€νΈ 쑰건(3κ³Ό 5μ λ°°μ) λ₯Ό ν΅κ³Όνλ κ° 12345678910111213# ν¨μν νλ‘κ·Έλλ°, μ¬κ·def sum(seq): if len(seq) == 0 : return 0 return seq[0] + sum(seq[1:])def until(n, filter_func, v): if v==n : return [] if filter_func(v): return[v] + until(n, filter_func, v+1) else : return until (n, filter_func, v+1) until(10, lambda x : x%3 == 0 or x%5 ==0 , 0) νμ΄λΈλ¦¬λν μ¬κ·μ κΈ°λ₯ λ¨μ μ 보μ 1sum(n for n in range(1, 10) if n %3 ==0 or n%5 == 0) μμ2 μ κ³±κ·Ό ꡬνκΈ° (Newton-Raphson μκ³ λ¦¬μ¦) 12def next_(n, x): return (x+n/x) /2 λͺ
λ Ήν νλ‘κ·Έλλ° 123f = lambda x : next_(n, x)a0 = 1.0 [ round(x,4) for x in (a0, f(a0), f(f(a0)), f(f(f(a0))),) ] ν¨μν νλ‘κ·Έλλ° 123456789101112131415def repeat(f, a): yield a for v in repeat(f, f(a)): # 무ν λ°λ³΅ yield v def within(diff, iterable): def head_tail(diff, a, iterable): b = next(iterable) if abs(a-b) <= diff : return b return head_tail(diff, b, iterable) return head_tail(diff, next(iterable), iterable) def sqrt(a0, diff, n): return within(diff, repeat(labmda x : next_(n,x), a0)) μ¬κ·μ μΌλ‘ μ κ·Όν λ, λͺ©ν(diff) μ μ΄μ μ λ§μΆ° μ½λ©μ΄ κ°λ₯νλ€ HOW? μμ ν¨μ μ»€λ§ 1κΈ ν¨μ μμν¨μ λμΌν μ
λ ₯μλ νμ κ°μ κ°μ λ°ν Side effect(global, nonlocal variable) μ μν₯μ λ°μΌλ©΄ μλλ€. 123f = lambda x : 2 ** x f(17)131072 λ¬λ 컀λΈκ° μμ§λ§, μ
λ ₯ κ°μ λν κ²°κ³Όλ₯Ό μμν μ μμ΄, ν
μ€νΈμ μ μ©νλ€ μ»€λ§, Currying μ¬λ¬κ°μ μΈμλ₯Ό κ°μ§ ν¨μλ₯Ό νΈμΆν κ²½μ°, νλΌλ―Έν°μ μλ³΄λ€ μ μ μμ νλΌλ―Έν°λ₯Ό μΈμλ‘ λ°μΌλ©΄ λλ½λ νλΌλ―Έν°λ₯Ό μΈμλ‘ λ°λλ€. 12345678910111213141516from pymonad import currydef systolic_bp(bmi, age, gender_mail, treatment): return 68.15+0.58*bmi+0.65*age+0.94*gender_male+6.44*treatmentsystolic_bp(25, 50, 1, 0)systolic_bp(25, 50, 0, 1)# Currying treated = systolic_bp(25,50,0)treated(0)115.15treated(1)121.59 μ©λμ λ§κ² μ°κΈ° κ°νΈν΄μ§λ€ -> μ¬μ¬μ©μ μ μ©ν΄μ§λ€ 1κΈ μλ―Ό / 1κΈ κ°μ²΄ / 1κΈ ν¨μ ν¨μλ₯Ό μΈμλ‘ μ 곡νκ³ λ€λ₯Έ ν¨μμ λν κ°μ λ°ν 쑰건 :: λ°νμ νκ²½μμ μΌκΈ κ°μ²΄μ¬μΌ νλ€. (μΌκΈ μλ―Ό > μΌκΈ κ°μ²΄ > μΌκΈ ν¨μ) 1κΈ μ‘°κ±΄ λ³μμ λ΄μ μ μμ΄μΌ νλ€ ν¨μμ μΈμλ‘ μ λ¬ν μ μλ€. ν¨μμ λ°νκ°μΌλ‘ μ λ¬ν μ μλ€. 12345a = 1 # λ³μμ λ΄μ μ μλ€.def f(num){ # λ§€κ° λ³μλ‘ μ λ¬μ΄ κ°λ₯νλ€ result = 1 + a return result # returnμΌλ‘ μ λ¬ν μ μλ€} 12345678910def example(a,b ,**kw): return a*b >>> type(example)< class 'function'>>>> example.__code__.co_varnames('a', 'b', 'kw')>>> example.__code__.co_argcount2 μ½λ ꡬνμ΄ κ°κ²°ν΄μ§ Closure (go, javascript) ꡬν κ°λ₯ ν¨μλ₯Ό μ€νν¨κ³Ό λμμ ν¨μμμ λ³μκ° μμ±λλ©° ν¨μλ₯Ό μ€ννλ λμ λ³μλ λ©λͺ¨λ¦¬μ μ μ§λλ€. 1234567891011121314151617181920package main func nextValue() func() int { i := 0 return func() int { i++ return i }} func main() { next := nextValue() println(next()) // 1 println(next()) // 2 println(next()) // 3 anotherNext := nextValue() println(anotherNext()) // 1 println(anotherNext()) // 2 ν¨μλ₯Ό νΈμΆν λλ§λ€ κΈ°μ‘΄μ μμ±νλ κ°μ μ μ§ν μ μλ€, λ³μ μ¬νμ© κ°λ₯ μΈλΆμ ν΄λΉ λ³μλ₯Ό λ
ΈμΆνμ§ μμ. μ μμΌλ‘ λ
ΈμΆλμ§λ μμ§λ§ μ μμ μΈ λ°©μμΌλ‘ μ¬μ©μ΄ κ°λ₯, μμ μ±μ΄ 보μ₯λ¨ μ°Έκ³ κΈ°μ‘΄μ μ¬κ³ λ°©μμ κΉ¨λΆμλ ν¨μν μ¬κ³ ν¨μν νλ‘κ·Έλλ° μμ½ functional python programming_pdf [javasript] 1κΈ μλ―Ό, 1κΈ κ°μ²΄, 1κΈ ν¨μ μ»€λ§ [javascript] hoisting, scope, closure","link":"/2020/01/05/functional/ν¨μνμΈμ΄_in_νμ΄μ¬_/"},{"title":"ν¨μν μΈμ΄ λͺ¨λλνΈ in νμ΄μ¬","text":"λͺ¨λλ ν¨ν΄ κ³μ°κ³Ό μλ¦¬κ° λ³΅μ‘ν΄μ! pythonμ PyMoand λΌμ΄λΈλ¬λ¦¬ μ¬μ©νμ¬ λͺ¨λλ ꡬν λ° μ΄ν΄ PyMoand? PyMonadλ κΈ°λ₯ μ€νμΌ νλ‘κ·Έλ¨μ ꡬννλ λ° μ¬μ©νκΈ° μν΄ λͺ¨λλ λ° κ΄λ ¨ λ°μ΄ν° μΆμν (νν°, μ ν리μΌμ΄μ
νν° λ° λͺ¨λ
Έ μμ΄λ)λ₯Ό ꡬννλ μμ λΌμ΄λΈλ¬λ¦¬μ
λλ€. Haskellμ λͺ¨λλμ μ΅μν μ¬λλ€μ μν΄ PyMonadλ νμ΄μ¬μμ λͺ¨λλλ₯Ό λΉ λ₯΄κ³ μ½κ² μ¬μ©ν μ μλλ‘ λ§μ κΈ°λ₯μ ꡬννλ κ²μ λͺ©νλ‘ν©λλ€. λͺ¨λλλ₯Ό μ¬μ©ν μ μ΄ μμ§λ§ κ΄μ¬μ΄μλ μ¬λλ€μκ² PyMonadλ Haskellμ λ°°μΈ νμμμ΄ μ½κ° λ μ©μν μμλ νκ²½μμ μ½κ² λ°°μΈ μμλ λ°©λ²μ
λλ€. Features λͺ¨λλλ₯Ό μ΄ν΄νκΈ° μν΄ κΈ°λ³Έ μμμΈ Curringμ νΉμ§κ³Ό ν©μ± ν¨μμ νΉμ§μ μμλ³΄κ² μ΅λλ€. Currying multiargument function κΈ°λ₯ μ 곡 123456789101112# Returns the first element of a list.@currydef head(aList): return aList[0]# Returns everything except the first element of the list.@currydef tail(aList): return aList[1:]second = head * tail # 'tail' will be applied first, then its result passed to 'head'second([1, 2, 3, 4]) # returns 2 ν¨μλ₯Ό λ³μμ²λΌ μ¬μ©ν μ μλ€ 1234567891011121314151617from pymonad.Reader import curry@currydef add(x, y): return x + y@currydef mul(x, y): return x * ycomp = add(7) * mul(2) # 'mul(2)' is evaluated first, and it's result passed to 'add(7)'comp(4) # returns 15# Composition order matters!comp = mul(2) * add(7)comp(4) # returns 22 컀λ§κ³Ό κ²°ν©νμ¬ ν©μ±ν¨μ ꡬν κ·Έλ λ€λ©΄ λͺ¨λλλ₯Ό λ€μ΄κ°κΈ° μ μ μ ν¨μ±ν¨μλ₯Ό μ¬μ©νμκΉ? λͺ¨λλμ κΈ°λ³Έ μμμΈ Functorμ Applicative Functorμ μλ¦¬λ‘ μ¬μ©λκΈ° λλ¬Έμ
λλ€. Functors, Applicative Functors Functor ν¨μμμ μνκ°κ³Ό κ²°κ³Ό κ°μ λͺ¨λ ν¬ν¨νλ κΈ°λ³Έ μμ Fmap , * λ‘ νν 1234567891011from pymonad.Maybe import *from pymonad.List import *# 'neg' knows nothing about functor types...def neg(x): return -x# ... but that doesn't stop us from using it anyway.neg * Just(9) # returns Just(-9)neg * Nothing # returns Nothingneg * List(1, 2, 3, 4) # returns List(-1, -2, -3, -4) μΈμ β9β κ° λ€μ΄μ€λ©΄ ν¨μμ κ²°κ³Όκ° μΆλ ₯λλ©° Nothing μνκ° λ€μ΄κ°λ©΄ Nothing μ κ²°κ³Ό κ°μ μ μ μλ€. Just μ Listλ Functor νΉμ§μ ꡬννκΈ° μν pymonadμ μ μ© λ³μμ 리μ€νΈ μλ£ κ΅¬μ‘°νμ Applicative Functors Functor μ Arguments νμ₯ Amap, & λ‘ νν μΈμ κ°μ νμ₯νμ¬ μ¬μ©νλ€. 12345678910# 'add' operates on simple types, not functors or applicatives...def add(x, y): return x + y# ... but we're going to use it on those types anyway.# Note that we're still using '*' but now in conjunction with '&'add * Just(7) & Just(8) # returns Just(15)add * Nothing & Just(8) # returns Nothingadd * Just(7) & Nothing # returns Nothingadd * List(1, 2, 3) & List(4, 5, 6) # returns List(5, 6, 7, 6, 7, 8, 7, 8, 9) & μ°μ°μ ν΅ν΄ μΈμ κ°μ μ΄μ΄ λ°μ μ μλ€. Monad Applicative Functorsμ νμ₯ Bind, >> μ°μ°μ μ΄μ© ν¨μλ₯Ό νμ₯νμ¬ μ¬μ©νλ€. 12345678910111213141516171819202122232425262728from pymonad.List import *from pymonad.Reader import curry# Takes a simple number type and returns a 'List' containing that value and it's negative.def positive_and_negative(x): return List(x, -x)# You can call 'positive_and_negative' normally.positive_and_negative(9) # returns List(9, -9)# Or you can create a List...x = List(9)# ... and then use '>>' to apply positive_and_negative'x >> positive_and_negative # also returns List(9, -9)# But 'x' could also have more than one value...x = List(1, 2)x >> positive_and_negative # returns List(1, -1, 2, -2)# And of course you can sequence partially applied functions.@currydef add_and_sub(x, y): return List(y + x, y - x)List(2) >> positive_and_negative >> add_and_sub(3) # List(2) # List(2, -2) # List(5, -1, 1, -5) ν¨μ νμ₯μ μ΄μ© >> λ₯Ό μ΄μ©, positive_and_negativeμ μΈμ κ°μΌλ‘ List(2) μ μ΄μ©νμ¬ List(2,-2)μ κ²°κ³Όκ°μ μ»μ List(2, -2)κ° add_and_sub(3) μ μΈμκ°μΌλ‘ λ€μ΄κ° List(5, -1, 1, -5)μ κ²°κ³Ό κ°μ λ°μ Monadic code >> μ°μ°μ μ΄μ© ν¨μλ₯Ό λλ€λ‘ λ체νμ¬ μ΄νμ ν¨μ ꡬνμ΄ κ°λ₯νλ€ 12345from pymonad.Maybe import *Just(9) >> (lambda x: # Here, 'x' takes the value '9'Just(8) >> (lambda y: # And 'y' takes the value '8'Just(x + y))) # 'Just(9 + 8)' or 'Just(17)' State Monad 12345678910111213141516171819202122@currydef add(x, y): return State(lambda old_state: (x + y, old_state + 1))@currydef subtract(y, x): @State def state_computation(old_state): if x - y < 0: return (0, old_state + 1) else: return (x - y, old_state + 1) return state_computation x = unit(State, 1) >> add(2) >> add(3) >> subtract(40) >> add(5)y = x(0)print(y)y = x.getResult(0) # computation result value 5 y = x.getState(0) # state value 4 old_stateλ‘ λμ κ° μ μμ΄μ State ν¨ν΄μ΄λΌ μΉν¨ Functional programming to Web Sever 1headers, contents = httpd(headers, request, [uploads]) μ΅μ ν μ°Έκ³ PyMonad ν¨μν νλ‘κ·Έλλ° in Python WikibooksHaskell μν€λΆμ€ λͺ¨λλ μ΄ν΄νκΈ°","link":"/2020/01/17/functional/ν¨μνμΈμ΄_λͺ¨λλ_in_νμ΄μ¬_.md/"},{"title":"Iterator Pattern","text":"λμμΈ ν¨ν΄ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ° μ€κ³μμ μμ£Ό λ°μνλ λ¬Έμ λ€μ νΌνκΈ° μν΄ μ¬μ©λλ ν¨ν΄ λ€λ§, μκ³ λ¦¬μ¦μ΄ μλλΌ μν©μ λ°λΌ μμ£Ό μ°μ΄λ μ€κ³ λ°©λ²μ μ 리ν μ½λ© λ°©λ²λ‘ μ΄λ©° λͺ¨λ μν©μ ν΄κ²°μ±
μ μλλ€. μ€μν κ²μ λμμΈ ν¨ν΄μ μ½λ§€μ΄λ κ²μ΄ μλλΌ κ·Έ ν¨ν΄μ΄ μ ν¨μ¨μ μΈ λ°©μμΈμ§λ₯Ό μ΄ν΄νμ¬μΌ νλ€. μ΄ν°λ μ΄ν°(iterator) ν¨ν΄ λ°λ³΅μ΄ νμν μλ£κ΅¬μ‘°λ₯Ό λͺ¨λ λμΌν μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μ κ·Όν μ μλλ‘ λ©μλλ₯Ό μ΄μ©ν΄ μλ£κ΅¬μ‘°λ₯Ό νμ©ν μ μλλ‘ ν΄μ€λ€. νμ΄μ¬μ κ²½μ°, μ΄ν°λ μ΄ν°μ μ λλ μ΄ν°λ₯Ό λ¬Άμ΄ λ¬Έλ²μΌλ‘ μκ°λμ΄ μμ΅λλ€. 12345678910111213141516171819202122# μ΄ν°λ μ΄ν°def __getitem__(self, index): return <next item>>>> L = [1,2,3]>>> i = iter(L)>>> print i<iterator object at 0x8116870>>>> i.next()1>>> i.next()2>>> i.next()3>>> i.next()Traceback (most recent call last): File \"<stdin>\", line 1, in ?StopIteration>>>for x in [1,2,3]: print(x) κ΅³μ΄ iter() ν¨μλ₯Ό μ¬μ©νμ§ μμλ for λ¬ΈμΌλ‘ μ κ·Όμ΄ κ°λ₯νλ€. μ΄κ²μ looping νλ λμ, python λ΄λΆμμ μμλ‘ listλ₯Ό iteratorλ‘ μλμΌλ‘ λ³νλ¨ 123456789101112131415161718192021222324252627282930313233# generatordef generate_ints(N): for i in range(N): yield i # generator expression>>> ( i for i in xrange(10) if i % 2 )<generator object <genexpr> at 0x7f6105d90960>#1 μ λλ μ΄ν° μ¬μ© μ΄μ , λ©λͺ¨λ¦¬ >>> import sys>>> sys.getsizeof( [i for i in xrange(100) if i % 2] ) # list536>>> sys.getsizeof( [i for i in xrange(1000) if i % 2] )4280>>> sys.getsizeof( (i for i in xrange(100) if i % 2) ) # generator80>>> sys.getsizeof( (i for i in xrange(1000) if i % 2) )80#2 μ λλ μ΄ν° μ¬μ© μ΄μ , Lazy evaluation def fibonacci_func(n): a,b = 0, 1 i = 0 while True: if (i > n): return yield a a, b = b, a+b i += 1fib = fibonacci_func(10)for x in fib: print x #1 Memory λ₯Ό ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μλ€. list λ list μμ μν λͺ¨λ λ°μ΄ν°λ₯Ό λ©λͺ¨λ¦¬μ μ μ¬νκΈ° λλ¬Έμ listμ ν¬κΈ° λ§νΌ μ°¨μ§νλ λ©λͺ¨λ¦¬ μ¬μ΄μ¦κ° λμ΄λκ² λλ€. νμ§λ§ generator μ κ²½μ° λ°μ΄ν° κ°μ νκΊΌλ²μ λ©λͺ¨λ¦¬μ μ μ¬ νλ κ²μ΄ μλλΌ next() λ©μλλ₯Ό ν΅ν΄ μ°¨λ‘λ‘ κ°μ μ κ·Όν λλ§λ€ λ©λͺ¨λ¦¬μ μ μ¬νλ λ°©μμ΄λ€. #2 Lazy evaluation μ§μ, λ©λͺ¨λ¦¬μμ ν¨μ¨μ± λ° λΆνμν μ°μ°μ λ°°μ κ° κ°λ₯νμ¬ ν¨μ¨μ μΈ νΌν¬λ¨Όμ€λ₯Ό κΈ°λν μ μλ€. itertools λΌμ΄λΈλ¬λ¦¬μμ λ€μν μ΄ν°λ μ΄ν°μ νμ© μ(iterator building block)λ₯Ό νμΈν μ μμ΅λλ€. Infinite Iterators: Iterator Arguments Results Example count() start, [step] start, start+step, start+2*step, β¦ count(10) --> 10 11 12 13 14 ... cycle() p p0, p1, β¦ plast, p0, p1, β¦ cycle('ABCD') --> A B C D A B C D ... repeat() elem [,n] elem, elem, elem, β¦ endlessly or up to n times repeat(10, 3) --> 10 10 10 Iterators terminating on the shortest input sequence: Iterator Arguments Results Example chain() p, q, β¦ p0, p1, β¦ plast, q0, q1, β¦ chain('ABC', 'DEF') --> A B C D E F compress() data, selectors (d[0] if s[0]), (d[1] if s[1]), β¦ compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F dropwhile() pred, seq seq[n], seq[n+1], starting when pred fails dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1 groupby() iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) ifilter() pred, seq elements of seq where pred(elem) is true ifilter(lambda x: x%2, range(10)) --> 1 3 5 7 9 ifilterfalse() pred, seq elements of seq where pred(elem) is false ifilterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8 islice() seq, [start,] stop [, step] elements from seq[start:stop:step] islice('ABCDEFG', 2, None) --> C D E F G imap() func, p, q, β¦ func(p0, q0), func(p1, q1), β¦ imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000 starmap() func, seq func(*seq[0]), func(*seq[1]), β¦ starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000 tee() it, n it1, it2, β¦ itn splits one iterator into n takewhile() pred, seq seq[0], seq[1], until pred fails takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4 izip() p, q, β¦ (p[0], q[0]), (p[1], q[1]), β¦ izip('ABCD', 'xy') --> Ax By izip_longest() p, q, β¦ (p[0], q[0]), (p[1], q[1]), β¦ izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- Combinatoric generators: Iterator Arguments Results product() p, q, β¦ [repeat=1] cartesian product, equivalent to a nested for-loop permutations() p[, r] r-length tuples, all possible orderings, no repeated elements combinations() p, r r-length tuples, in sorted order, no repeated elements combinations_with_replacement() p, r r-length tuples, in sorted order, with repeated elements product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC combinations('ABCD', 2) AB AC AD BC BD CD combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD κ·Έ μΈμλ μ΄ν°λ μ΄ν°μ Map, fliter, reduce & lambda λ₯Ό μ¬μ©νμ¬ μ΄ν°λ μ΄ν°μ ν¨μκ° λ§€νμ΄ κ°λ₯ν©λλ€. 1234567891011# map items = [1,2,3,4,5]list(map(lambda x : x**2, items))# filternumber_list = raunge(-5, 5)list(filter(lambda x : x<0, number_list))# reducefrom functools import reduce value = reduce((lambda x,y : x+y), (x for x in range(1, 101)) μ λλ μ΄ν° μ₯μ (λ©λͺ¨λ¦¬, Lazy) + ν¨μν μΈμ΄(κ°κ²°μ±, Lazy) μ°Έκ³ λμμΈ ν¨ν΄μ΄λ λ무μν€_λμμΈν¨ν΄ itertools γ
γ
γ
γ· - μ΄ν°λ μ΄ν°, μ λλ μ΄ν° python 2.2 doc λμμΈ ν¨ν΄ - μ€λ¬΄νΈ νμ¬λ ν¨ν΄ - νμ
νμ¬λ ν¨ν΄ - Logbridge","link":"/2020/02/06/Design_Pattern/Iterator_Pattern/"},{"title":"Observer Pattern","text":"λμμΈ ν¨ν΄ μ€μν κ²μ λμμΈ ν¨ν΄μ μ½λ§€μ΄λ κ²μ΄ μλλΌ κ·Έ ν¨ν΄μ΄ μ ν¨μ¨μ μΈ λ°©μμΈμ§λ₯Ό μ΄ν΄νμ¬μΌ νλ€. λμμΈ ν¨ν΄ λ λ²μ§Έ λ°νμλ£μ΄λ©° μ±κΈν΄, μ΅μ λ² ν¨ν΄μ λν΄ λ°ννκ² μ΅λλ€. μ λ μ λ² μκ°κ³Ό κ°μ΄ ν¨ν΄μ λν΄ λ€μκ³Ό κ°μ κ΄μ μΌλ‘ μ κ·Όνμμ΅λλ€. ν¨ν΄μ΄ λ μμΈ(μ΄λ€ μ μ΄ ν¨μ¨μ μΈκ°), 보μν΄μΌν μ (to μ‘κΈ°μ λ°°μ°κΈ°) ν¨ν΄μ΄ νλ νλ‘κ·Έλλ° μΈμ΄μμλ μ΄λ»κ² μ¬μ©λλκ°? μ΅μ λ² ν¨ν΄ μ΅μ λ² ν¨ν΄(observer pattern)μ κ°μ²΄μ μν λ³νλ₯Ό κ΄μ°°νλ κ΄μ°°μλ€, μ¦ μ΅μ λ²λ€μ λͺ©λ‘μ κ°μ²΄μ λ±λ‘νμ¬ μν λ³νκ° μμ λλ§λ€ λ©μλ λ±μ ν΅ν΄ κ°μ²΄κ° μ§μ λͺ©λ‘μ κ° μ΅μ λ²μκ² ν΅μ§νλλ‘ νλ λμμΈ ν¨ν΄ μ
λλ€. **μ μ¬μ©ν κΉ ? ** κ°μ²΄ κ°μ μΌλ λ€ μ’
μμ± κ΄κ³λ₯Ό κ΄λ¦¬ν λ μ¬μ©λ©λλ€. κ°μ²΄ κ°μ λ°μ ν κ΄κ³μμ΄ κ°μ²΄ κ°μ μΌλ λ€ μ’
μμ±μ μ μν΄μΌ ν©λλ€. νλμ κ°μ²΄κ° μνλ₯Ό λ³κ²½ν λ κ°λ°©ν μμ μ’
μ κ°μ²΄κ° μλμΌλ‘ μ
λ°μ΄νΈλλλ‘ ν΄μΌν©λλ€. ν κ°μ²΄κ° κ°λ°© λ μμ λ€λ₯Έ κ°μ²΄λ₯Ό ν΅μ§ ν μ μμ΄μΌν©λλ€. μ΄λ»κ² ꡬνν κΉ? 12345678910111213141516171819202122class Observable(object): def __init__(self) -> None: self._observers = [] def register_observer(self, observer) -> None: self._observers.append(observer) def notify_observers(self, *args, **kwargs) -> None: for observer in self._observers: observer.notify(self, *args, **kwargs)class Observer(object): def __init__(self, observable) -> None: observable.register_observer(self) def notify(self, observable, *args, **kwargs) -> None: print('Got', args, kwargs, 'From', observable)subject = Observable()observer = Observer(subject)subject.notify_observers('test') 주체μ λ°λΌ Push, Pull λ°©μμΌλ‘ λλ μ§λλ€. (μλ£ λ³΄κ° νμ γ
γ
) νκ³ νμ§λ§, μ΅μ λ² ν¨ν΄μ νκ³λ μ‘΄μ¬ν©λλ€. κ°μ²΄ κ°μ μΌλ λ€ μ’
μμ± μ μλ λμμ νΉμ μ’
μ κ°μ²΄μ μ°κ²°νκΈ° λλ¬Έμ μ΅ν΅μ±μ΄ μμ΅λλ€. μ΄λ μ±λ₯μ΄ νμν μν©μμλ (μ΄λΉ μμ² λ² μ€νλλ μ μμ€ μ»€λ ꡬ쑰λ₯Ό κ³ λ €ν λ) κ³ λ―Όν΄λ΄μΌν λ¬Έμ μ
λλ€. λ°μ νκ² μ°κ²°λ κ°μ²΄λ μΌλΆ μλ리μ€μμ ꡬννκΈ°κ° μ΄λ €μΈ μ μμΌλ©° μΈν°νμ΄μ€κ° λ€λ₯Έ μ¬λ¬ κ°μ²΄λ₯Ό μ°Έμ‘°νκ³ μ
λ°μ΄νΈνλ λ°©λ²μ μκ³ μκΈ° λλ¬Έμ μ¬μ¬μ© ν μ μμ΄ κΈ°λνμ§ μμ κ²°κ³Όλ₯Ό μ΄λν μ μμ΅λλ€. λν, μ΅μ λ² ν¨ν΄μΈ κ²½μ° λ©λͺ¨λ¦¬ λμλ₯Ό μ΄λν μ μμ΅λλ€. So what can possibly go wrong? In a runtime where memory is managed automatically like Java or C#, the subject holds a strong reference to the observers, keeping them alive. The strong reference from the subject (the observed object) to the observer, prevents the observer (and any objects it references) from being garbage collected until the observer is unregistered. A memory leak happens, if the observer fails to unregister from the subject when it no longer needs to receive notifications. In our countdown timer example if observers do not call unregister when they become invisible, they will receive notifications and waste CPU cycles updating invisible UI elements. This issue is called Lapsed Listener Problem. If you implement the observer pattern in C++ (no garbage collection, memory is managed manually) and you call delete on one of the observers without unregistering it from the subject then you are in trouble. Now you have a dangling pointer that points to invalid data. Whenever the subject notifies its observers a segmentation fault will be raised. Always unregister your listeners unless they are interested in receiving notifications. Another approach for dealing with lapsed listeners (observers) is to use Weak References. The below implementation of CountDownTimer uses weak references to keep track of registered observers. If the only references to an instance are weak references, then the instance becomes a candidate for Garbage Collection. In contrast to strong references, weak references donβt prevent garbage collector to finilize the instance and reclaim its memory. μ¬μ€ μ΄λ μ΅μ λ² ν¨ν΄λΏλ§ μλλΌ OOP κ°μ²΄λ₯Ό λ€λ£° λ 곡ν΅μ μΌλ‘ λ°μν μ μλ λ¬Έμ μ
λλ€. λ¨μ μΈ ν΄κ²°λ°©λ²μ Weakreference λ₯Ό μ¬μ©νμ¬ μλμ μΌλ‘ κ°λΉμ§ 컬λ μ
μ μ¬μ©νλ€κ³ λͺ
μνλ©΄ μλ°©ν μ μμ΅λλ€. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100package codekata.observer;import java.lang.ref.WeakReference;import java.util.LinkedList;import java.util.List;public class CountDownTimer { private static long ONE_SECOND = 1000L; private long countDownMillis; private long elapsedTimeSinceLastTick; private long totalElapsedTime; private List<WeakReference<CountDownObserver>> observers = new LinkedList<>(); public CountDownTimer(long initialValue) { this.countDownMillis = initialValue; } //Called every frame public void update(long deltaTime) { if (isFinished()) { return; } if (totalElapsedTime == 0) { notifyStart(); } totalElapsedTime += deltaTime; elapsedTimeSinceLastTick += deltaTime; if (elapsedTimeSinceLastTick >= ONE_SECOND) { elapsedTimeSinceLastTick = 0; notifyCountDown(); } if (isFinished()) { notifyCountDown(); notifyFinish(); } } private boolean isFinished() { return totalElapsedTime >= countDownMillis; } private void notifyCountDown() { for(WeakReference<CountDownObserver> ref : this.observers) { CountDownObserver observer = ref.get(); if (observer != null) { observer.onCountDown( totalElapsedTime, Math.max(0, (countDownMillis - totalElapsedTime))); } else { System.out.println(\"!!! DELETED\"); } } } private void notifyStart() { for(WeakReference<CountDownObserver> ref : this.observers) { CountDownObserver observer = ref.get(); if (observer != null) { observer.onStart(); } } } private void notifyFinish() { for(WeakReference<CountDownObserver> ref : this.observers) { CountDownObserver observer = ref.get(); if (observer != null) { observer.onFinish(); } } } public void registerObserver(CountDownObserver observer) { WeakReference<CountDownObserver> weakReference = findWeakReference(observer); if (weakReference == null) { weakReference = new WeakReference<>(observer); this.observers.add(weakReference); } } public void unregisterObserver(CountDownObserver observer) { WeakReference<CountDownObserver> weakReference = findWeakReference(observer); if (weakReference != null) { this.observers.remove(weakReference); } } private WeakReference<CountDownObserver> findWeakReference(CountDownObserver observer) { WeakReference<CountDownObserver> weakReference = null; for(WeakReference<CountDownObserver> ref : this.observers) { if (ref.get() == observer) { weakReference = ref; } } return weakReference; }} μλ° κ³ μμ λμμ΄ νμν©λλ€. κ·ΈλΌμλ λΆκ΅¬νκ³ β¦ μ΅μ λ² ν¨ν΄μμμ κ°μ²΄ κ΄λ¦¬λ λ§ν¬λ¦¬μ€νΈ λ‘ μ μ₯ν©λλ€. νμ§λ§ μ΄λ λ¨μΌ μ€λ λμμλ§ ν΄λΉλλ μκΈ°λ‘ λ©ν°μ€λ λ μν©μμ Thread-safe μν©μ 보μ₯νμ§ λͺ»ν©λλ€. κ·Έλ λ€λ©΄ μ΄λμ μ¬μ©ν΄λ³ΌκΉ? λνμ μΌλ‘ MVC μν€ν
μ²μμ μ¬μ©ν μ μμ΅λλ€. MVC λ Model-View-Controller λ‘ μννΈμ¨μ΄ λμμΈ ν¨ν΄μ
λλ€. μ¬μ©μ μΈν°νμ΄μ€λ‘λΆν° λΉμ§λμ€ λ‘μ§μ λΆλ¦¬νμ¬ μ ν리μΌμ΄μ
μ μκ°μ μμλ κ·Έ μ΄λ©΄μμ μ€νλλ λΉμ¦λμ€ λ‘μ§μ μλ‘ μν₯ μμ΄ μ½κ² κ³ μΉ μ μλ μ ν리μΌμ΄μ
μ λ§λ€ μ μμ΅λλ€. ![Observer Pattern](C:\\Users\\user\\Desktop\\곡λΆ\\CS Study\\Design Pattern\\Observer Pattern.PNG) Modelμ μ ν리μΌμ΄μ
μ μ 보(λ°μ΄ν°)λ₯Ό λνλ΄λ©°,Viewλ ν
μ€νΈ, 체ν¬λ°μ€ νλͺ© λ±κ³Ό κ°μ μ¬μ©μ μΈν°νμ΄μ€ μμλ₯Ό λνλ΄κ³ , Controllerλ λ°μ΄ν°μ λΉμ¦λμ€ λ‘μ§ μ¬μ΄μ μνΈλμμ κ΄λ¦¬νλ€. MVCκ° νμ©λ μλ‘ Qt, MFC νλ μμν¬κ° μλ λ° MFC νλ μμν¬μμμ μ΅μλ² ν¨ν΄ μ¬μ©μ μ΄ν΄λ³΄κ² μ΅λλ€. ![MFC1](C:\\Users\\user\\Desktop\\곡λΆ\\CS Study\\Design Pattern\\MFC1.PNG) λ¨Όμ λ·°λ₯Ό μνλ κ³³μ λ°°μΉν©λλ€. ![MFC2](C:\\Users\\user\\Desktop\\곡λΆ\\CS Study\\Design Pattern\\MFC2.PNG) λ·°λ₯Ό λ°°μΉν¨κ³Ό λμμ 컨νΈλ‘€λ¬ μ½λκ° μλμΌλ‘ μμ±λ©λλ€. ![MFC3](C:\\Users\\user\\Desktop\\곡λΆ\\CS Study\\Design Pattern\\MFC3.PNG) 컨νΈλ‘€λ¬ μ½λλ₯Ό μμ±νμ¬ μ΄λ²€νΈκ° λ°μνμ μ ꡬνν λ΄μ©μ μμ±ν©λλ€. μ¬μ©μ²? MVC κ°μ κ²½μ° κΈ°λ₯μ On/OFF μΈ μνκ° λ€μμΌ κ²½μ° μ¬μ©νκΈ° μ’μ΅λλ€. κ³°νλ μ΄μ΄μμμ λμμ κ΄λ ¨ κΈ°λ₯ μ΄λ²€νΈλ νκΈμ μ¬λ¬ κΈ°λ₯μ μλ‘ μκ°νλ©΄ μ΄ν΄νκΈ° νΈν κ² κ°μ΅λλ€. μ°Έκ³ μν€λ°±κ³Ό μ΅μλ²ν¨ν΄ μ΅μλ² λ°©μ λκ°μ§ https://doohyun.tistory.com/82 λ‘κΉ
- μ΅μ λ² vs μ±
μμ°μ μ΅μλ²ν¨ν΄μμμ λ©λͺ¨λ¦¬λ¦ https://glikmakesworld.tistory.com/3 μμ https://nowonbun.tistory.com/480 μ€λ¬΄","link":"/2020/01/21/Design_Pattern/Observer_Pattern/"},{"title":"Strategy Pattern","text":"λμμΈ ν¨ν΄ μ€μν κ²μ λμμΈ ν¨ν΄μ μ½λ§€μ΄λ κ²μ΄ μλλΌ κ·Έ ν¨ν΄μ΄ μ ν¨μ¨μ μΈ λ°©μμΈμ§λ₯Ό μ΄ν΄νμ¬μΌ νλ€. λμμΈ ν¨ν΄ μΈ λ²μ§Έ λ°νμλ£μ΄λ©° μ€νΈλ ν°μ§, ν©ν 리 ν¨ν΄μ λν΄ λ°ννκ² μ΅λλ€. μ λ μ λ² μκ°κ³Ό κ°μ΄ ν¨ν΄μ λν΄ λ€μκ³Ό κ°μ κ΄μ μΌλ‘ μ κ·Όνμμ΅λλ€. ν¨ν΄μ΄ λ μμΈ(μ΄λ€ μ μ΄ ν¨μ¨μ μΈκ°), 보μν΄μΌν μ (to μ‘κΈ°μ λ°°μ°κΈ°) ν¨ν΄μ΄ νλ νλ‘κ·Έλλ° μΈμ΄μμλ μ΄λ»κ² μ¬μ©λλκ°? μ€νΈλ ν°μ§ ν¨ν΄ μ λ΅ ν¨ν΄ (μ μ±
ν¨ν΄μ΄λΌκ³ λ ν¨)μ λ°νμμ μκ³ λ¦¬μ¦μ μ νν μμλ νλ μννΈμ¨μ΄ λμμΈ ν¨ν΄μ
λλ€. μ½λλ λ¨μΌ μκ³ λ¦¬μ¦μ μ§μ ꡬννλ λμ μκ³ λ¦¬μ¦ κ³μ΄μμ μ¬μ©ν μκ³ λ¦¬μ¦μ λν λ°νμ λͺ
λ Ήμ μμ ν©λλ€. μ λ΅μ μ¬μ©νλ©΄ μκ³ λ¦¬μ¦μ μ¬μ©νλ ν΄λΌμ΄μΈνΈμ μκ³ λ¦¬μ¦μ΄ λ
립μ μΌλ‘ λ¬λΌμ§ μ μμ΅λλ€. μ λ΅μ κ°λ§ (Gamma) λ±μ μν₯λ ₯μλ μ±
λμμΈ ν¨ν΄μ ν¬ν¨ λ ν¨ν΄ μ€ νλμ
λλ€. μ μ°νκ³ μ¬μ¬μ© κ°λ₯ν κ°μ²΄ μ§ν₯ μννΈμ¨μ΄λ₯Ό λμμΈνλ λ°©λ²μ μ€λͺ
νκΈ° μν΄ λμμΈ ν¨ν΄μ μ¬μ©νλ κ°λ
μ λμ€ννμ΅λλ€. λ°νμκΉμ§ μ¬μ©ν μκ³ λ¦¬μ¦μ λν κ²°μ μ μ°κΈ°νλ©΄ νΈμΆ μ½λλ₯Όλ³΄λ€ μ μ°νκ³ μ¬μ¬μ© ν μ μμ΅λλ€. μλ₯Ό λ€μ΄, λ€μ΄μ€λ λ°μ΄ν°μ λν μ ν¨μ± κ²μ¬λ₯Ό μννλ ν΄λμ€λ μ λ΅ μ νμ μ¬μ©νμ¬ λ°μ΄ν° νμ, λ°μ΄ν° μμ€, μ¬μ©μ μ ν λλ κΈ°ν μλ³ μμμ λ°λΌ μ ν¨μ± κ²μ¬ μκ³ λ¦¬μ¦μ μ νν μ μμ΅λλ€. μ΄λ¬ν μμλ λ°νμκΉμ§ μλ €μ§μ§ μμμΌλ©° μμ ν λ€λ₯Έ μ ν¨μ± κ²μ¬λ₯Ό μνν΄μΌ ν μλ μμ΅λλ€. μ ν¨μ± κ²μ¬ κ°μ²΄μ λ³λλ‘ μΊ‘μν λ μ ν¨μ± κ²μ¬ μκ³ λ¦¬μ¦ (μ λ΅)μ μ½λ 볡μ μμ΄ μμ€ν
(λλ λ€λ₯Έ μμ€ν
)μ λ€λ₯Έ μμμμλ λ€λ₯Έ μ ν¨μ± κ²μ¬ κ°μ²΄μ μν΄ μ¬μ©λ μ μμ΅λλ€. μΌλ°μ μΌλ‘ μ λ΅ ν¨ν΄μ μΌλΆ μ½λμ λν μ°Έμ‘°λ₯Ό λ°μ΄ν° ꡬ쑰μ μ μ₯νκ³ κ²μν©λλ€. μ΄λ λ€μ΄ν°λΈ ν¨μ ν¬μΈν°, 1 κΈ ν¨μ, κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ° μΈμ΄μ ν΄λμ€ λλ ν΄λμ€ μΈμ€ν΄μ€μ κ°μ λ©μ»€λμ¦ λλ 리νλ μ
μ ν΅ν΄ μΈμ΄ ꡬνμ λ΄λΆ μ½λ μ μ₯μμ μ‘μΈμ€νμ¬ λ¬μ± ν μ μμ΅λλ€. UML μ λ΅ν¨ν΄μ νμμ±κ³Ό ꡬν μ λ΅ ν¨ν΄μ μ νμνκ³ , μ΄λ»κ² ꡬνν κ² μΈμ§ κ°λ¨ν μμ λ‘ μ€λͺ
νκ² μ΅λλ€.λ€μ μμ λ μΊλ¦ν°κ° 무기λ₯Ό κ°μ§κ³ 곡격νλ ν΄λμ€λ₯Ό ꡬνν μμ μ
λλ€. μΈμ΄λ νμ΄μ¬μ
λλ€. 123456class Character: def __init__(): self.weapon = new Knife() def doAttack(): print(\"Attack Knife!!\") Knife().Attack() μ€νμ μ무 λ¬Έμ μμ§λ§, βμΊλ¦ν°λ λ¨κ²μ μμ‘΄λ ννβ μ
λλ€. λ§μ½ μΊλ¦ν°μ κ²μ μ₯μ°©μν€κ³ μΆλ€λ©΄ μ΄λ»κ² ν΄μΌν κΉμ? 123456class Character: def __init__(): self.weapon = new Sword() def doAttack(): print(\"Attack Sword!!\") Sword().Attack() μΌλ©λ‘ μ½λλ₯Ό λ³κ²½νμ¬ μΊλ¦ν°μ κ²μ μ₯μ°©νμμ΅λλ€. νμ§λ§ λ¨κ²κ³Ό κ²μ λ³κ²½ν΄μΌνλ μΊλ¦ν°κ° νμνλ©΄? ν¬κ²μ΄νΈ μ€νμ΄ μμλ©λλ€λ³κ²½ μμ²μ΄ λ°μν λλ§λ€ μ½λλ₯Ό μμ ν΄μΌ ν©λλ€. μ μ§λ³΄μκ° μ΄λ €μμ§λ©° μ΄λ μΊλ¦ν°κ° 무기μ μμ‘΄λμμ΄ λ°μν©λλ€. μ΄λ₯Ό μ€νλ§ νλ μμν¬μμ μ¬μ©νλ κ°λ
μΌλ‘ μ€λͺ
νμλ©΄ DI:Dependency Injection, μμ‘΄μ± μ£Όμ
λΌ ν©λλ€. μμ‘΄μ±μ κΉ¨λ리기 μν΄μ μ΄λ»κ² ν΄μΌν κΉμ? κ°λ¨ν©λλ€. Weapon μ ν΄λμ€λ‘ λ§λ€μ΄ μΊ‘μνμν€λ©΄ λ©λλ€. μΊ‘μνλ₯Ό μν΄ μΈν°νμ΄μ€λ₯Ό μ¬μ©νμμ΅λλ€. μΈν°νμ΄μ€λ ν΄λμ€λ νμ₯μ μν΄ open/closed principle(OCP)μ νΈνλλ©°, λμμ μ¬μ©νλ ν΄λμ€λ₯Ό μ€λ¨νμ§ μκ³ λμμ λ³κ²½ν μ μμΌλ©°, μ€μν μ½λ λ³κ²½μμ΄ μ¬μ© λ νΉμ ꡬνμ λ³κ²½νμ¬ ν΄λμ€κ° λμκ°μ μ ν ν μ μμ΅λλ€. λμμΈ νμλΏλ§ μλλΌ λ°νμμλ λμμ λ³κ²½ν μ μμ΅λλ€. μΈν°νμ΄μ€λ₯Ό ν΅ν΄ ꡬνλ μμ λ λ€μκ³Ό κ°μ΅λλ€. open/closed principle(OCP), κ°λ°© / νμ μμΉ : ν΄λμ€λ νμ₯μ μν΄ κ°λ°©λμ΄μΌνμ§λ§ μμ μ μν΄ νμλμ΄μΌνλ€λ μμΉμ
λλ€. 1234567891011121314151617181920212223242526272829303132import abc class Weapon: __metaclass__ = abc.ABCMeta @abc.abstractmethod def doAttack(self): passclass Knife(Weapon): def doAttack(self): print(\"Attack Knife!!\")class Sword(Weapon): def doAttack(self): print(\"Attack Sword!!\")class Character: def __init__(self, weapon): super(Character, self).__init__() self.weapon = weapon def setWeapon(self,weapon): self.weapon = weapon def doAttack(self): self.weapon.doAttack()c = Character(Knife())c.doAttack()c.setWeapon(Sword())c.doAttack() μμ 무기 λ³κ²½ μμ²μ λν΄ λ©μΈ ν¨μμμ κ²°μ ν μ μκ² λμμ΅λλ€. μ¦ λ¬΄κΈ°λ₯Ό μ μ΄νλ μ μ΄κΆμ΄ μΊλ¦ν°μ μλ κ²μ΄ μλλΌ λ©μΈ ν¨μλ‘ μμ λμμΌλ―λ‘ μ΄λ₯Ό μ μ΄κ° μμ λμλ€λΌκ³ νλ©° μ€νλ§μμ μ¬μ©νλ κΈ°μ μμ΄λ‘ IOC:Inversion of Control, μ μ΄μ μμ μ΄λΌ ν©λλ€. κ·Έλ λ€λ©΄ μ§κΈμ? μ¬μ€ νμ΄μ¬μμλ κ°μ²΄νλ₯Ό ν΅ν΄ μ λ΅ ν¨ν΄μ ꡬνν νμλ μμ΅λλ€. ν¨μ μ체λ₯Ό λ³μνμν€λ©΄ λ§€μ° κΉλνκ³ κ°λ¨ν μ λ΅ ν¨ν΄μ ꡬνν μ μκ±°λ μ. λ€μμ Pycon 2009 μ λμμΈ ν¨ν΄μΌλ‘ μκ°λ μ λ΅ ν¨ν΄ μμ μ
λλ€. 12345678910def strategy_add(a, b): return a + bdef strategy_minus(a, b): return a - bsolver = strategy_addprint solver(1, 2)solver = strategy_minusprint solver(2, 1) λ§€μ° κΉλνλλ€ ! μ λ΅ ν¨ν΄μ λμ΄μ μμ μ λ΅ ν¨ν΄μ μκ°λ‘ λ°νμμ μκ³ λ¦¬μ¦μ μ νν μμλ νλ μννΈμ¨μ΄ λμμΈ ν¨ν΄μΌλ‘ μ΄λ₯Ό IOC:Inversion of Control, μ μ΄μ μμ μ΄λΌκ³ μκ°λλ Έμ΅λλ€. μ λ μ λ΅ ν¨ν΄μ΄μΈμλ Ioc λ₯Ό ꡬνν μ μλ λ°©λ²μΌλ‘ μλ²λ¦¬μ€ μν€ν
μ²κ° μλ€ μκ°νμ¬ μκ°νμ¬ νλμ μμ λ₯Ό μκ°νκ³ μ ν©λλ€. μ μλΆνμ°κ΅¬μμμ μλ²λ¦¬ν¬ μν€ν
μ² μ°κ΅¬κ³Όμ λ‘ κ°λ° μ€μΈ Openfxμ μν€ν
μ² μ
λλ€. κΈ°λ₯μ μ μ¬ νλ μμν¬λ‘ AWSμ λλ€λΌκ³ μκ°νμλ©΄ νΈν κ² κ°μ΅λλ€. μ¬μ©μκ° μλ²μ μ μ½μμ΄ κ΅¬νλΆμ μ½λλ§ κ°λ°νμ¬ ν΄λΉ νλ μμν¬μ λ°°ν¬νλ©΄ μλμΌλ‘ μλ²λ‘ λ¬Άμ¬ μ€νλλ ꡬ쑰μ
λλ€. μ΄λ»κ² ꡬνλλ κ²μΌκΉμ? μλ μμ λ Openfxμ μν€ν
μ²μμ Openfx-fn μμ Executer μ μλ² κ΅¬ν μ½λλ₯Ό μΌλΆ κ°μ Έμμ΅λλ€. 1234567891011121314151617import impdef loadPlugin(moduleName, funcName): mod = imp.load_source(funcName, moduleName) # load user function from module return getattr(mod, funcName)def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) watcherServer = FxWatcherServicer(loadPlugin(moduleName, funcName)) fxwatcher_pb2_grpc.add_FxWatcherServicer_to_server( watcherServer, server) server.add_insecure_port('[::]:'+fxwatcherPort)if __name__ == '__main__': serve() ν΅μ¬μ imp λΌμ΄λΈλ¬λ¦¬μμ μ 곡νλ loadPlugin κΈ°λ₯μ
λλ€. μΈλΆ λΌμ΄λΈλ¬λ¦¬μ ν¨μλ₯Ό λ³μλ‘ λ°μ Serverλ‘ λ±λ‘νλ κΈ°λ₯μ μννλ©°, λ°νμμ μμμ ν¨μλ₯Ό λΆλ¬μ μλ²μ λ±λ‘νμ¬ μλ²λ₯Ό μμν©λλ€. μ΄μΈμλ λ컀μ μ΄λ―Έμ§ κΈ°μ μ νμ©νμ¬ λ°νμμκ°μ λ¦μΆ° μ¬μ©μ ν¨μλ₯Ό λ°°ν¬ν λ μλ²μ μ΄λ―Έμ§μ λ¬Άμ¬ μλ²λ‘ μ€νλλ ꡬ쑰λ₯Ό κ°μ§κ³ μμ΅λλ€. μ λ΅ ν¨ν΄μ νμ© λ€μμ λμΌν λ©μλλ₯Ό κ°μ§ ν΄λμ€λ€μ λν΄ μ΄λ»κ² μ¬μ©λκ³ μλ μ§, gRPC Serverμ ꡬν μ½λ μμ λ₯Ό 보면μ μ€λͺ
νκ² μ΅λλ€. 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556// A ServerOption sets options such as credentials, codec and keepalive parameters, etc.type ServerOption interface { apply(*serverOptions)}// κΈ°λ³Έ type EmptyServerOption struct{}func (EmptyServerOption) apply(*serverOptions) {}// μ¬μ©μ μ΅μ
μ μν ꡬ쑰체 type funcServerOption struct { f func(*serverOptions)}// μ¬μ©μ μ΅μ
ν¨μ μ€νfunc (fdo *funcServerOption) apply(do *serverOptions) { fdo.f(do)}// μ¬μ©μ μ΅μ
μμ± ν¨μfunc newFuncServerOption(f func(*serverOptions)) *funcServerOption { return &funcServerOption{ f: f, }}func NewServer(opt ...ServerOption) *Server { opts := defaultServerOptions for _, o := range opt { o.apply(&opts) } s := &Server{ lis: make(map[net.Listener]bool), opts: opts, conns: make(map[transport.ServerTransport]bool), m: make(map[string]*service), quit: grpcsync.NewEvent(), done: grpcsync.NewEvent(), czData: new(channelzData), } chainUnaryServerInterceptors(s) chainStreamServerInterceptors(s) s.cv = sync.NewCond(&s.mu) if EnableTracing { _, file, line, _ := runtime.Caller(1) s.events = trace.NewEventLog(\"grpc.Server\", fmt.Sprintf(\"%s:%d\", file, line)) } if channelz.IsOn() { s.channelzID = channelz.RegisterServer(&channelzServer{s}, \"\") } return s} apply λ₯Ό νλ©΄ λκ° λ¬λΌμ§λ 건λ°? β¦ μ°Έκ³ μν€λ°±κ³Ό_μ λ΅ν¨ν΄ μ μ΄μ μμ κ³Ό μμ‘΄μ± μ£Όμ
κ°λ¨ μ 리 νμ΄μ½ 2009_ λ€μμΈ ν¨ν΄ μκ° μ μλΆνμ°κ΅¬μ μλ²λ¦¬μ€ μν€ν
μ², Openfx github gRPC github","link":"/2020/03/05/Design_Pattern/Strategy_Pattern/"},{"title":"Singleton Pattern","text":"λμμΈ ν¨ν΄(2) μ€μν κ²μ λμμΈ ν¨ν΄μ μ½λ§€μ΄λ κ²μ΄ μλλΌ κ·Έ ν¨ν΄μ΄ μ ν¨μ¨μ μΈ λ°©μμΈμ§λ₯Ό μ΄ν΄νμ¬μΌ νλ€. λμμΈ ν¨ν΄ λ λ²μ§Έ λ°νμλ£μ΄λ©° μ±κΈν΄, μ΅μ λ² ν¨ν΄μ λν΄ λ°ννκ² μ΅λλ€. μ λ μ λ² μκ°κ³Ό κ°μ΄ ν¨ν΄μ λν΄ λ€μκ³Ό κ°μ κ΄μ μΌλ‘ μ κ·Όνμμ΅λλ€. ν¨ν΄μ΄ λ μμΈ(μ΄λ€ μ μ΄ ν¨μ¨μ μΈκ°), 보μν΄μΌν μ (to μ‘κΈ°μ λ°°μ°κΈ°) ν¨ν΄μ΄ νλ νλ‘κ·Έλλ° μΈμ΄μμλ μ΄λ»κ² μ¬μ©λλκ°? μ±κΈν΄ ν¨ν΄ μ±κΈν΄ ν¨ν΄(Singleton pattern)μ λ°λ₯΄λ ν΄λμ€λ, μμ±μκ° μ¬λ¬ μ°¨λ‘ νΈμΆλλλΌλ μ€μ λ‘ μμ±λλ κ°μ²΄λ νλμ΄κ³ μ΅μ΄ μμ± μ΄νμ νΈμΆλ μμ±μλ μ΅μ΄μ μμ±μκ° μμ±ν κ°μ²΄λ₯Ό 리ν΄νλ€. μ΄μ κ°μ λμμΈ μ νμ μ±κΈν΄ ν¨ν΄μ΄λΌκ³ νλ€. μ£Όλ‘ κ³΅ν΅λ κ°μ²΄λ₯Ό μ¬λ¬κ° μμ±ν΄μ μ¬μ©νλ DBCP(DataBase Connection Pool)μ κ°μ μν©μμ λ§μ΄ μ¬μ©λλ€. [μν€λ―Έλ¬] μ μ¬μ©ν κΉ ? ν΄λμ€ λ΄μμ μΈμ€ν΄μ€κ° λ¨ νλλΏμμ 보μ₯νλ―λ‘, νλ‘κ·Έλ¨ μ μμμ ν΄λΉ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ°λ‘ μ»μ μ μκ³ , λΆνμν λ©λͺ¨λ¦¬ λλΉλ₯Ό μ΅μννλ€. μ΄λ»κ² ꡬνν κΉ ? __new__ μμ±μ μ λ©νν΄λμ€ λ₯Ό ν΅ν΄ ꡬνν μ±κΈν΄ 123456789101112131415class Singleton(object): def __new__(self): if not hasattr(self, 'instance'): self.Instance = super(Singleton, self).__new__(self) return self.self.instance s = singleton()s2 = singleton()print(\"Object created\", s)print(\"Object created\", s2)outputObject created <__main__.Singleton object at 0x0000028014344EF0>Object created <__main__.Singleton object at 0x0000028014344EF0> python μ __new__ μμ±μλ₯Ό μ¬μ©νμ¬ μ±κΈν΄ ꡬν __new__ ? __init__ μ΄ λ°ν κ°μ κ°μ§ μ μλ κ²μ 보μν μμ±μ 1234567891011class MetaSingleton(type): _instances = {} def __call__(self, *args, **kwargs): if self not in self._instances: self._instances[self] = super(MetaSingleton, self).__call__(*args, **kwargs) return self._instances[self] class Logger(metaclass = MetaSingleton): pass μ±κΈν΄ λ³ν, κ°μ²΄λ λ€λ₯΄μ§λ§ μνλ₯Ό 곡μ ν¨ 1234567891011121314151617class Singleton2: __shard_state = {\"1\":\"2\"} def __init__(self): self.x = 1 self.__dict__ = self.__shared_state pass b1 = Singleton2();b2 = Singleton2();b1.x = 5output<__main__.LazySingleton object at 0x0000028014357F60><__main__.LazySingleton object at 0x0000028014357F98>{'1': '2', 'x': 5}{'1': '2', 'x': 5} μ±κΈν΄μ λ¬Έμ μ μ±κΈν΄ μΈμ€ν΄μ€κ° λ§μ μΌμ νκ±°λ λ°μ΄ν°λ₯Ό 곡μ μν¬ κ²½μ° λ€λ₯Έ ν΄λμ€μ μΈμ€ν΄μ€λ€κ°μ κ²°ν©λκ° λμμ Έ OOP μμΉ, "κ°λ°©-νμ μμΉ"μ μν΄νκ² λλ€. λ°λΌμ μμ μ΄ μ΄λ €μμ§κ³ ν
μ€νΈνκΈ° μ΄λ €μμ§λ€. λν, λ©ν°μ°λ λ νκ²½μμ λκΈ°νμ²λ¦¬λ₯Ό μνλ©΄ μΈμ€ν΄μ€κ° λ κ°κ° μμ±λλ κ²½μ°κ° λ°μν μ μμ κ²°κ³Όμ μΌλ‘ βgotoλ μ°λ©΄ μλΌβ , βμ μ κ°μ²΄λ μμ’μκ±°μΌ!β λΌλ λ§ μ²λΌ κΌ νμν κ²½μ°κ° μλλ©΄ μ§μν΄μΌνλ€. λ©ν°μ°λ λμμ μμ ν μ±ν΄ν€ ν΄λμ€ μμ±νκΈ° Java ν
μ€νΈνμΌλ©° 3κ°μ§μ λ°©λ²μ μκ°νκ² μ΅λλ€. Synchronized λ₯Ό ν΅ν Thread safe Lazy initialization(κ²μΌλ₯Έ μ΄κΈ°ν) 1234567891011121314public class ThreadSafeLazyInitialization{ private static ThreadSafeLazyInitialization instance; private ThreadSafeLazyInitialization(){} public static synchronized ThreadSafeLazyInitialization getInstance(){ if(instance == null){ instance = new ThreadSafeLazyInitialization(); } return instance; } } private μμ±μλ‘ μΈλΆμμμ μμ±μ λ§μμΌλ, synchronized νΉμ±μ ν° μ±λ₯μ νκ° λ°μνλ―λ‘ κΆμ₯νμ§ μλλ€ Synchronized λμ κ°μ λ¬Έ μ¬μ©νκΈ°, Thread safe lazy initialization + Double-checked locking 123456789101112131415161718public class ThreadSafeLazyInitialization { private volatile static ThreadSafeLazyInitialization instance; private ThreadSafeLazyInitialization(){} public static ThreadSafeLazyInitialization getInstance(){ if(instance == null){ synchronized (ThreadSafeLazyInitialization.class) { if(instance == null) instance = new ThreadSafeLazyInitialization(); } } return instance; }} synchronized λ₯Ό μ¬μ©νλ κ²μ΄ μλλΌ If λ¬Έ λλ²(νμΈ, λκΈ°ν)μΌλ‘ μ±λ₯ μ νλ₯Ό νΌνμ§λ§ μλ²½ν λ°©λ²(κ°λ°μκ° μ§μ λ¬Έμ λ₯Ό ννΌν΄μΌν μ½λλ₯Ό μ§μΌν¨)μ μλλλ€. final μ μ¬μ©ν Initialization on demand holder idiom 123456789101112public class Something { private Something() { } private static class LazyHolder { public static final Something INSTANCE = new Something(); } public static Something getInstance() { return LazyHolder.INSTANCE; }} κ°λ°μκ° μ§μ λκΈ°ν λ¬Έμ μ λν΄ μ½λλ₯Ό μμ±νμ¬ λ¬Έμ λ₯Ό ννΌνλ € νλ€λ©΄ νλ‘κ·Έλ¨ κ΅¬μ‘°κ° κ·Έ λ§νΌ 볡μ‘ν΄μ§κ³ λΉμ© λ¬Έμ κ° μκΈΈ μ μκ³ νΉν μ μ§λ³΄μ μΈ‘λ©΄μμ μ΄μμ μ΄μ§ λͺ»ν©λλ€. μ΄ λ°©λ²μ JVMμ ν΄λμ€ μ΄κΈ°ν κ³Όμ μμ 보μ₯λλ μμμ νΉμ±μ μ΄μ©νμ¬ μ±κΈν΄μ μ΄κΈ°ν λ¬Έμ μ λν μ±
μμ JVMμ λ λκΈ΄λ€. holderμμ μ μΈλ instanceκ° staticμ΄κΈ° λλ¬Έμ ν΄λμ€ λ‘λ©μμ μ νλ²λ§ νΈμΆλ κ²μ΄λ©° finalμ μ¬μ©ν΄ λ€μ κ°μ΄ ν λΉλμ§ μλλ‘ λ§λ λ°©λ². *** κ°μ₯ λ§μ΄ μ¬μ©νκ³ μΌλ°μ μΈ Singleton ν΄λμ€ μ¬μ© λ°©λ²μ΄λ€.** ν νΈλ λμμμ μ±κΈν΄? μ¬κΈ°κΉμ§ μ΄ν΄λ³΄μμ λ, λ°°(κ·Έλ₯ μ½λλ‘ μ¬μ©νκΈ°)λ³΄λ€ λ°°κΌ½(μ±κΈν΄ ν¨ν΄ μ¬μ©)μ΄ λ ν° μν©μ΄λΌ λκΌμ΅λλ€. κ·Έλμ νμ
μμλ μ±κΈν΄μ μ¬μ©ν΄μΌν μν©μΌ λ μ€μ μ¬μ©νλ? κ° κΆκΈν΄μ μκ°ν΄λ΄€μ΅λλ€. μν€λ―Έλ¬λ₯Ό μ°Έκ³ νμ λ μ±κΈν΄μ νμ©μ²λ DBCP(DataBase Connection Pool)μ κ°μ μν©μ
λλ€. κ·Έλ¬λ©΄ ν νΈλλμμλ DBCPλ₯Ό μ±κΈν΄μ ν΅ν΄ νμ©νκ³ μμκΉμ? λ΅λ³λΆν° λ리면, ꡬκΈ(go, Kotlin)μμλ μ±κΈν΄μ Initialization on demand holder idiom μ λ¬Έλ²μΌλ‘ ꡬννλ μΆμΈμ
λλ€. go - Once.do νμ© 12345678910111213141516171819202122232425262728293031323334353637var once sync.Oncetype DriverPg struct { conn string}// variavel Globalvar instance *DriverPgfunc Connect() *DriverPg { once.Do(func() { instance = &DriverPg{conn: \"DriverConnectPostgres\"} //DB μ°κ²° μ²λ¦¬ }) return instance}func main() { // chamada go func() { time.Sleep(time.Millisecond * 600) fmt.Println(*Connect()) }() // 100 goroutine for i := 0; i < 100; i++ { go func(ix int) { time.Sleep(time.Millisecond * 60) fmt.Println(ix, \" = \", Connect().conn) }(i) } fmt.Scanln()} λκΈ°λΌμ΄λΈλ¬λ¦¬μ Once keyword μ΄μ©νμ¬ Initialization on demand holder idiom ꡬν kotlin- Object νμ© 123456789101112object Payroll { //object ν΄λμ€ μμ±μΌλ‘ μ±κΈν΄μ ꡬν val allEmplyees = arrayListOf<Person>() fun calculateSalary() { //... }}//μ¬μ©Payroll.calculateSalary() //μ±κΈν΄μ²λΌ . μΌλ‘ μ κ·ΌPayroll.allEmplyees.add(Person(\"zerog\", Company(\"zerog\", Address(\"\")))) κ°μ²΄(Object)λ ν΄λμ€ μ μΈκ³Ό κ·Έ ν΄λμ€μ μν λ¨μΌ μΈμ€ν΄μ€μ μμ±μ λμμ μ²λ¦¬ν΄μ£ΌκΈ° λλ¬Έμ μ±κΈν€μ μ¬μ©νκΈ° μ ν©ν©λλ€. double-checked locking κ°μ locking μκ³ λ¦¬μ¦μ μμ‘΄νλ κ² μμ΄ thread-safe νκ³ lazy ν μ΄κΈ°νλ₯Ό κ°λ₯νκ² ν΄ μ£ΌκΈ° λλ¬Έμ JVMμμ μ±κΈν€μ ꡬννλ λ°©λ²μΌλ‘ μ νΈλ©λλ€. μ½νλ¦°μμ κ°λ¨νκ² objectλ₯Ό μ μΈνλ©΄, μμ νκ³ ν¨μ¨μ μΈ μ±κΈν€ ꡬνμ 보μ₯λ°μ μ μμ΅λλ€. μ 리 μ±κΈν€μ μ리μ ꡬνλ°©λ²μ μ΄ν΄λ³΄μμ΅λλ€. μ μ κ°μ²΄λ₯Ό μμ±νμ¬ μ κ·Όνμ¬ λ©λͺ¨λ¦¬ μΈ‘λ©΄μ ν¨μ¨μ±μ κΈ°λνλ ν¨ν΄μ΄μ§λ§, μ°λ λμμμ μ±κΈν€κ³Ό OOP κΈ°λ²μ μμ μ±μ μν΄ Initialization on demand holder idiom κΈ°λ²μμ¬μ©νμ¬ μ±κΈν€μ ꡬννλ κ²μ΄ λ°λμ§ν©λλ€. λλΆμ΄ ν κ΅¬κΈ μΈμ΄(go, kotilin)μμλ ν΄λΉ κΈ°λ²μ΄ λ¬Έλ²μΌλ‘ μκ°λμ΄μμΌλ©° μ¬μ©νμλ λ° μ°Έκ³ νμλ©΄ λκ² μ΅λλ€. μ°Έκ³ μν€λ°±κ³Ό_μ±κΈν΄ ν¨ν΄ https://tourspace.tistory.com/109 https://takhyeongmin.github.io/2019/06/24/HowToKotlinSingleTon/ https://fenderist.tistory.com/109 https://www.fun-coding.org/PL&OOP2-2.html κΈ°λ³Έμ μΈ μ±κΈν€ ꡬνλ°©λ² 5κ°μ§ μ±κΈν€μ κ³ λν μ±κΈν€ λ¬Έμ μ κ³Ό 3κ°μ§ ν΄κ²°λ°©μ κ³ λ-μ±κΈν€ μ½νλ¦°-μ±κΈν€","link":"/2020/01/29/Design_Pattern/SingleTon_Pattern/"},{"title":"μλ²λ¦¬μ€ μ»΄ν¨ν
ν΅μ¬ μ리 μ΄ν΄","text":"Serverless Computing μλ²λ¦¬μ€ μ»΄ν¨ν
(Serverless Computing)λ IT μΈνλΌ κ΄λ¦¬ μμ΄ λͺ¨λ κΈ°λ₯μ μꡬμ¬νμ λν΄ ν¨μλ₯Ό νΈμΆνμ¬ μ²λ¦¬νλ ν΄λΌμ°λ μ»΄ν¨ν
ν¨λ¬λ€μμ
λλ€. μ¬μ©μλ νμν λΉμ¦λμ€ λ‘μ§λ§ ν¨μλ‘ κ°λ°νλ©΄ λ©λλ€. **IT μΈνλΌλ?** μ ν리μΌμ΄μ
μ κ°λμν€κΈ° μν΄ νμν νλμ¨μ΄λ OS, λ―Έλ€μ¨μ΄, λ€νΈμν¬ λ± μμ€ν
μ κΈ°λ°μ λ§ν©λλ€. μμ€ν
μꡬμ¬ν λκ°μ§ κΈ°λ₯μ μꡬμ¬ν : μ΄λ€ κΈ°λ₯μ νλμ§, 무μμ ν μ μλμ§ λΉκΈ°λ₯μ μꡬμ¬ν : μμ€ν
μ μ±λ₯, μμ μ±, νμ₯μ±, 보μ λ± μλ²λ¦¬μ€ ν¨μ μ (Python) 12def Handler(req): return req.input μλ²λ¦¬μ€ μΆμΈ 2019λ
κ°νΈλ(Gartner)κ° λ°νν μΈνλΌ μ‘°μ§μ κ°μ₯ μν₯μ λ―ΈμΉ μμ 10κ°μ κΈ°μ μ€, μλ²λ¦¬μ€ μ»΄ν¨ν
μ΄ 1μ νΈλλ κΈ°μ λ‘ μ μ λμμ΅λλ€. Why? μλ²λ¦¬μ€λ§μ μ°¨λ³μ±μ λΉ λ₯Έ κ°λ°μ±, μ μ°ν νμ₯μ± κ³Ό μ λ ΄ν μ΄μ λΉμ©μ
λλ€. #### **λΉ λ₯Έ κ°λ°μ±** μμ μκ°ν΄λλ¦° μλ²λ¦¬μ€ ν¨μ μμ²λΌ κ°λ°μλ νμν λΉμ¦λμ€ κΈ°λ₯λ§ μ§μ€νμ¬ κ°λ°ν μ μμΌλ©° λΉ λ₯Έ κ°λ°μ±μ 보μ₯ν©λλ€. 12def Handler(req): return req.input μ μ°ν νμ₯μ± μλ²λ¦¬μ€ νλ«νΌμμλ μ¬μ©μκ° νμλ‘ νλ μκ°λμλ§ μλ²κ° μ΄μ©λλ©° κ·Έ μκ°λ§νΌλ§ λΉμ©μ΄ μ²κ΅¬λ©λλ€. λν νΉμ 쑰건μ μ€μ νμ§ μμλ κΈκ²©ν νΈλν½ λ³νμ μ μ°ν λμμ΄ κ°λ₯ν©λλ€. μ΄λ μλ²λ¦¬μ€μ κΈ°λ° κΈ°μ μΈ μΏ λ²λ€ν°μ€κ° μ 곡νλ κΈ°λ₯μΌλ‘ μ€ν μ€μΌμΌλ§μ ν΅ν΄ μ½κ² ꡬνμ΄ κ°λ₯ν©λλ€. AutoScaling ? λ¨Όμ Scalingμ΄λ μλΉμ€ μμ²μ΄ λμ΄λλ©΄ μ΄λ₯Ό μμ©νκΈ° μν΄ μλ²μ μλ₯Ό λλ € μ°μ° λ₯λ ₯(capacity)μ ν₯μμν€κ³ λ°λλ‘ μλΉμ€ μμ²μ΄ μ€κ² λλ©΄ λΆνμν μλ²μ μλ₯Ό μ€μ΄λ actionμ λ§ν©λλ€. Auto Scalingλ λ¬Έμ κ·Έλλ‘ μ΄λ¬ν scaling acationμ΄ μλμΌλ‘ μ΄λ£¨μ΄μ§λ μλΉμ€λ₯Ό λ§ν©λλ€. μλμ κ·Έλ¦Όμ²λΌ μκ°μ λ°λΌ μλΉμ€ μμ²(λΆμ μ€μ )μ΄ λκ±°λ μ€μ΄λλ μν©μ λ§κ² μλμΌλ‘ μλ²μ μλ₯Ό μ‘°μ νλ©° μ΄μ λΉμ©μ μ€μ΄λ©° κΈκ²©ν νΈλν½ λ³νμ μ μ°ν λμμ΄ κ°λ₯ν©λλ€. νμ¬ μ€ν μ€μΌμΌλ§μ μλ²λ¦¬μ€μ κΈ°λ° κΈ°μ μΈ μΏ λ²λ€ν°μ€μμ μ 곡νλ κΈ°λ₯μΌλ‘ μ€μ κ° κΈ°μ
μ ν΅ν΄ μλμΌλ‘ μ‘°μ μ΄ κ°λ₯ν©λλ€. μ λ ΄ν μ΄μ λΉμ© μλ²λ¦¬μ€μμλ λ μ λ ΄ν μ΄μ λΉμ©μ μ 곡ν μ μμ΅λλ€. μλ²μ μλ₯Ό 0κΉμ§ μ€μΌμΌν μ μλ AutoScaling to Zero κΈ°λ₯μ μ 곡νκΈ° λλ¬Έμ
λλ€. ##### AutoScaling to Zero μ€ν μ€μΌμΌμΌμ νμ₯ κ°λ
μΌλ‘ μ€μΌμΌν κ°μμ μλ₯Ό 0κΉμ§ μ‘°μ ν μ μλ κΈ°λ₯μ
λλ€. νμ¬ μΏ λ²λ€ν°μ€μμμ μ€ν μ€μΌμΌλ§ κΈ°λ₯μ 1~N κΉμ§μ μ€μ κ°μ μ 곡νλ©° 0κΉμ§μ Scale Downμ λν΄μλ λ³λμ κ°λ°μ΄ νμν©λλ€. HOW? μΏ λ²λ€ν°μ€ 컨νΈλ‘€λ¬, ReplicaSet λͺ¨λν°λ§ λꡬ, νλ‘λ©ν
μ°μ€ **μΏ λ²λ€ν°μ€ ReplicaSet** μΏ λ²λ€ν°μ€λ νλ‘μΈμ€λ₯Ό 격리μν€λ κ°μν κΈ°μ μΈ λ컀 컨ν
μ΄λμ μ€μΌμ€νΈλ μ΄μ
λꡬμ
λλ€. μΏ λ²λ€ν°μ€λ 컨ν
μ΄λνλ μν¬λ‘λμ μλΉμ€λ₯Ό κ΄λ¦¬νκΈ° μν κΈ°λ₯μ μ 곡νλ©°, νμ₯ κ°λ₯ν μ€νμμ€ νλ«νΌμΌλ‘, μ μΈμ ꡬμ±κ³Ό μλνλ₯Ό λͺ¨λ μ§μν©λλ€. νμ¬ λλΆλΆμ μλ²λ¦¬μ€ νλ«νΌλ€μ μΏ λ²λ€ν°μ€λ₯Ό λ°νμΌλ‘ μ€κ³λμμ΅λλ€. ReplicaSetμ μΏ λ²λ€ν°μ€μ κΈ°λ³Έμ μΈ Pod λ₯Ό κ΄λ¦¬νλ 컨νΈλ‘€λ¬λ‘ μ§μ λ μ«μλ‘ Podλ₯Ό κΈ°λμν€κ³ , κ΄λ¦¬νλ μν μ μνν©λλ€. μ¬κΈ°μ Podλ κ°μ₯ κΈ°λ³Έμ μΈ λ°°ν¬ λ¨μλ‘, 컨ν
μ΄λλ₯Ό ν¬ν¨νλ λ¨μμ
λλ€. 123456789101112131415161718192021apiVersion: apps/v1kind: ReplicaSet # λ ν리카μ
metadata: name: frontend labels: app: guestbook tier: frontendspec: # μΌμ΄μ€μ λ°λΌ λ ν리카λ₯Ό μμ νλ€. replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: php-redis image: gcr.io/google_samples/gb-frontend:v3 123456$ kubectl get pods NAME READY STATUS RESTARTS AGEfrontend-b2zdv 1/1 Running 0 6m36sfrontend-vcmts 1/1 Running 0 6m36sfrontend-wtsmm 1/1 Running 0 6m36s νλ‘λ©ν
μ°μ€ Prometheusλ μ€νμμ€ μμ€ν
λͺ¨λν°λ§ λꡬμ
λλ€. κ΅¬μ‘°κ° κ°λ¨ν΄μ μ΄μμ΄ μ½κ³ , κ°λ ₯ν 쿼리 κΈ°λ₯μ κ°μ§κ³ μμΌλ©°, κ·ΈλΌνλ(Grafana) λ₯Ό ν΅ν μκ°νλ₯Ό μ§μν©λλ€. 무μλ³΄λ€ λμ μ€ν μμ€ μνκ³λ₯Ό κΈ°λ°μΌλ‘ ν΄μ, λ§μ μμ€ν
μ λͺ¨λν°λ§ν μ μλ λ€μν νλ¬κ·ΈμΈμ κ°μ§κ³ μλ κ²μ΄ κ°μ₯ ν° μ₯μ μ κ°μ§κ³ μμ΅λλ€. νλ‘λ©ν
μ°μ€μ λ°μ΄ν° μμ§λ°©μμΌλ‘λ Pull λ°©μμ μ¬μ©νμ¬, νλ‘λ©ν
μ°μ€ μλ²μ ν΄λΌμ΄μΈνΈλ₯Ό λ±λ‘νλ©΄ νλ‘λ©ν
μ°μ€κ° μ£ΌκΈ°μ μΌλ‘ ν΄λΌμ΄μΈνΈμ μ μν΄μ λ°μ΄ν°λ₯Ό κ°μ Έμ€λ λ°©μμ μ·¨ν©λλ€. AutoScaling to Zero μ리 μ¬μ©μκ° νΈμΆνμ§ μμ ν¨μλ€μ μ°Ύμ νλ μλ₯Ό 0μΌλ‘ μ‘°μ νλ©΄ λ νλ‘λ©ν
μ°μ€λ PromQLμ΄λΌλ 쿼리 μΈμ΄λ₯Ό ν΅ν΄ μ¬μ©μκ° μνλ λ©νΈλ¦ κ°μ μ»μ μ μμ΅λλ€. μλμ 쿼리문μ μλ²λ¦¬μ€μ λͺ¨λ ν¨μλ₯Ό λμμΌλ‘ NλΆκ° νΈμΆ νμ λ³λλμ μ»μ΅λλ€. 1rate(gateway_function_invocation_total[Nm]) μμ 쿼리 κ²°κ³Όκ°μμ Valueκ° 0 μΈ κ²μ 5λΆλμ ν¨μ νΈμΆμ΄ 0μΈ κ²μ λ»ν©λλ€. 0μΈ ν¨μλ₯Ό λμμΌλ‘ μΏ λ²λ€ν°μ€ Replica Setμ 0μΌλ‘ μ‘°μ ν μ μμ΅λλ€. 1$ kubectl scale deploy echo --replicas=0 -n openfx-fn 1234567$ kubectl get rs -n openfx-fnNAME DESIRED CURRENT READY AGEecho-dcf65bb86 0 0 0 46decho2-59d9f474bb 1 1 1 46decho3-6bc7f58976 1 1 1 46decho4-7b6dd65d6b 1 1 1 46decho5-7754d4fd44 1 1 1 46d μΏ λ²λ€ν°μ€κ° μ 곡νλ 리μμ€ νμΈ λͺ
λ Ήμ΄λ₯Ό ν΅ν΄ μ€ν μ€μΌμΌλ§λ ν¨μμ 리μμ€λ₯Ό νμΈν μ μμ΅λλ€. Replicasetμ΄ 1μΌ κ²½μ° λ¦¬μμ€ μ¬μ©λ 123$ kubectl top pods -n dcf-functionNAME CPU(cores) MEMORY(bytes) echo-7fb466b4f-6cdcd 14m 22Mi Replicasetμ΄ 0μΌ κ²½μ° λ¦¬μμ€ μ¬μ©λ 12$ kubectl top pods -n dcf-functionNAME CPU(cores) MEMORY(bytes) 리μμ€ μ¬μ©λμ΄ μμΌλ―λ‘ λͺ©λ‘μ ν΄λΉ ν¨μκ° μλ κ²μ νμΈν μ μμ΅λλ€. Real World μ€μ μμ© μλ²λ¦¬μ€ νλ μμν¬μμ μ€ν μ€μΌμΌλ§ μ λ‘λ₯Ό μ΄λ»κ² μ¬μ©νλ μ§ νμΈν΄λ³΄κ² μ΅λλ€. μ΄ν΄λ³Ό μλ²λ¦¬μ€ νλ μμν¬λ μ€νμμ€ μλ²λ¦¬μ€ νλ«νΌμΌλ‘ κ°μ₯ λ§μ starλ₯Ό 보μ νκ³ μλ Openfaas μ
λλ€. Openfaas λ Faas-idlerμ΄λΌλ μ€λΈμ νΈλ₯Ό ν΅ν΄ μ€ν μ€μΌμΌλ§ μ λ‘λ₯Ό μ 곡ν©λλ€. μν€ν
μ²μ μ²λ¦¬ μ½λλ λ€μκ³Ό κ°μ΅λλ€. β νλ‘λ©ν
μ°μ€μ 쿼리μ Faas-nets λ΄λΆμ μΏ λ²λ€ν°μ€ replicasetμ μ΄μ©ν¨ β Question μΏ λ²λ€ν°μ€μμ μ€ν μ€μΌμΌλ§ μλ₯Ό 0κΉμ§ μ 곡νμ§ μλκ°? μ°Έκ³ [1] 2019 κ°νΈλ μΈνλΌ κΈ°μ λν₯ [2] μ€ν μ€μΌμΌλ§ κ°λ
μ€λͺ
Naver [3] μλ²λ¦¬μ€ μ»΄ν¨ν
μκ°_μΌμ± SDS [4] νλ‘λ©ν
μ°μ€ 쿼리 κΈ°λ³Έ μ΄ν΄νκΈ° [5] μΏ λ²λ€ν°μ€ λ ν리카μ
[6] Openfaas/faas-idler","link":"/2020/07/21/Serverless/μλ²λ¦¬μ€_μ»΄ν¨ν
_ν΅μ¬_μ리_μ΄ν΄_/"}],"tags":[{"name":"Design Pattern","slug":"Design-Pattern","link":"/tags/Design-Pattern/"},{"name":"Python","slug":"Python","link":"/tags/Python/"},{"name":"Functional Programming","slug":"Functional-Programming","link":"/tags/Functional-Programming/"},{"name":"Hexo","slug":"Hexo","link":"/tags/Hexo/"},{"name":"Blog","slug":"Blog","link":"/tags/Blog/"},{"name":"Golang","slug":"Golang","link":"/tags/Golang/"},{"name":"Kubernetes","slug":"Kubernetes","link":"/tags/Kubernetes/"},{"name":"prometheus","slug":"prometheus","link":"/tags/prometheus/"},{"name":"Serverless Computing","slug":"Serverless-Computing","link":"/tags/Serverless-Computing/"}],"categories":[{"name":"Programming Paradigm","slug":"Programming-Paradigm","link":"/categories/Programming-Paradigm/"},{"name":"Tools","slug":"Tools","link":"/categories/Tools/"},{"name":"Functional Programming","slug":"Programming-Paradigm/Functional-Programming","link":"/categories/Programming-Paradigm/Functional-Programming/"},{"name":"Hexo","slug":"Tools/Hexo","link":"/categories/Tools/Hexo/"},{"name":"develop","slug":"develop","link":"/categories/develop/"},{"name":"Design Pattern","slug":"develop/Design-Pattern","link":"/categories/develop/Design-Pattern/"},{"name":"Golang","slug":"Golang","link":"/categories/Golang/"},{"name":"Kubernetes","slug":"Golang/Kubernetes","link":"/categories/Golang/Kubernetes/"},{"name":"prometheus","slug":"Golang/Kubernetes/prometheus","link":"/categories/Golang/Kubernetes/prometheus/"},{"name":"Serverless Computing","slug":"Golang/Kubernetes/prometheus/Serverless-Computing","link":"/categories/Golang/Kubernetes/prometheus/Serverless-Computing/"}]}