디자인 패턴의 아름다움 - 1. 개요

1. 개요 1.1 코드 설계를 배우는 이유 효율적인 코드 작성 = 데이터 구조 + 알고리즘 유지 보수가 용이한 고품질 코드 = 코드 설계에 대한 지식 1.1.1 고품질의 코드 작성 1.1.2 복잡한 코드 개발 다루기 소프트웨어 개발 시 만나는 어려움의 유형 2가지 높은 수준의 기술을 필요로 하는 경우: 자율 주행, 비디오 인식, AI 높은 수준의 기술을 필요로 하지 않는 대규모 프로젝트: 이 책에서 다룰 내용 1.1.3 프로그래머의 기본 능력 1.1.4 경력 개발에 필요한 기술 1.2 코드 품질 평가 방법 1.2.1 유지 보수성 기존의 코드 설계를 손상하거나 새로운 버그를 발생시키지 않고도 빠르게 코드를 수정하거나 추가할 수 있는 상태 코드가 간결하고 가독성이 높으며 확장성이 높다면 코드의 유지 보수도 쉬움 코드가 명확하게 계층화되어 있으며, 높은 모듈성, 높은 응집도와 낮은 결합도를 가짐 1.2.2 가독성 훌륭한 프로그래머는 사람이 이해할 수 있는 코드를 작성한다. 제가 중요하게 생각하는 것 중 하나 1.2.3 확장성 약간 수정하는 것만으로도 혹은 전혀 수정하지 않고도 확장을 통해 새로운 기능을 추가하는 것 요구 사항의 미래 변화에 대처할 수 있는 코드의 능력 1.2.4 유연성 추상적인 평가 기준이기 때문에 정의하기 쉽지 않음 확장을 위한 인터페이스가 준비되어 있음 기본적으로 재사용 가능한 많은 모듈과 클래스 등이 기존 코드에 추상화된 형태로 이미 제공 클래스가 다양한 사용 시나리오에 대응하고, 다양한 요구를 충족 가능 1.2.5 간결성 널리 알려진 KISS(Keep It Simple, Stupid) 원칙 많은 프로그래머는 단순한 코드에 복잡한 디자인 패턴을 도입하는 것을 좋아한다. 그러나 고수준의 프로그래머는 종종 간단한 방법으로 복잡한 문제를 해결한다. 저의 코딩 스타일 중 하나 1.2.6 재사용성 반복적인 코드 작성을 최소화하고 기존 코드를 재사용하는 것 단일 책임 원칙(single Responsibility principle) DRY(Don’t repeat yourself) 원칙 1.2.7 테스트 용이성 이 책에서 처음 보는 기준인데, 중요할 것 같네요. 1.3 고품질 코드를 작성하는 방법 1.3.1 객체지향 세 가지의 프로그래밍 패러다임(절차적, 함수형, 객체지향) 중에서 객체지향 프로그래밍이 가장 대중적임 이 책에서는 객체지향에 대해 마스터하는 것을 목표로 함 1.3.2 설계 원칙 각각의 설계 원칙이 어떤 문제와 응용 시나리오를 해결하는데 사용되는 것인지 파악해야 한다 모두 마스터해야만 설계 원칙을 프로젝트에 유연하고 적절하게 적용할 수 있다 설계 원칙은 디자인 패턴보다 더 보편적이고 중요한 것이다. 1.3.3 디자인 패턴 자주 접하게 되는 일부 설계 문제에 대해 요약된 솔루션 또는 설계 사상 1.3.4 코딩 규칙 주로 가독성 문제 해결 1.3.5 리팩터링 기법 1.4 과도한 설계를 피하는 방법 1.4.1 코드 설계의 원래 의도는 코드 품질을 향상시키는 것이다 1.4.2 코드 설계의 원칙은 앞에 문제가 있고, 뒤에 방안이 있다는 것이다 1.4.3 코드 설계의 응용 시나리오는 복잡한 코드에 적용되어야 한다 디자인 패턴을 적용하는 목적은 디커플링, 즉 더 나은 코드 구조를 사용하여 단일 책임을 위해 큰 조각을 작은 클래스로 분할하여 코드가 높은 응집도와 낮은 결합도의 특성을 충족하도록 하는 것이다. 1.4.4 지속적인 리팩토링은 과도한 설계를 효과적으로 방지할 수 있다 실현 가능성이 낮은 미래의 요구 사항을 위해 처음부터 디자인 패턴을 적용하기보다, 진짜 문제가 발생했을 때 이를 해결하기 위한 디자인 패턴을 사용하는 것을 고려하는 것이다. 1.4.5 특정 시나리오 외의 코드 설계에 대해 이야기하지 않는다

5월 18, 2025 · Jaejin Jang

양귀자 - 모순

ChatGPT가 나온 이후로 포스팅할 맛이 안 나요. 왜냐하면 물어보면 다 알려주거든요~ 저 또한 검색하지 않고 바로 ChatGPT한테 물어보는 경우가 늘어서 이거 뭐~ 포스팅해 봐야 의미가 있나 싶더라고요. 그래도 다시 적어 볼까 합니다. 그냥 제가 하던 일중에 하나니까요. 인생이란 어쩌면 어떤 일(Job만의 의미가 아닌)을 할지 찾아나가는 과정일지도 모릅니다. ...

5월 6, 2025 · Jaejin Jang

워드 비교 기능 오류 해결 방법

워드 비교 기능을 이용하여 아주~ 나이스하게 한 문서의 작업을 끝내고 다음 문서를 비교하려고 하니 오류가 뜨더군요. 정말 필요로 하던 꿀 기능인데, 이렇게나 쉽게 오류가 발생해서 못쓰나 낙담하다가 혹시나 해결책이 있을까봐 싶어서 찾아봤습니다. ...

2월 14, 2025 · Jaejin Jang

아니 이런 기능이 있었다고?! 워드 비교 기능에 대하여

지금 일하는 곳에서 분기에 한 번은 규격 문서의 변경사항을 파악하여 정리하는 일을 하고 있습니다. 규격문서는 깃허브에 PR(Pull Request)를 올리는 것 처럼, CR(Change Request) 문서를 통하여 변경사항을 반영하는데요. ...

2월 14, 2025 · Jaejin Jang

해밀턴 카키 필드 머피 구매후기

2024.11.19 추가 팔아버렸습니다.. 시계는 마음에 드는데, 핸드폰에서 오는 알림을 못 받으니까 안차게 되네요 ㅜ 마음가짐만 챙기겠습니다. 좋은 시계였다.. 나랑 안 맞을 뿐! adios 스포츠용 시계밖에 없어서 평범한 시계 하나 사야지하는 생각을 갖고 있었는데 이번에 구매를 했습니다. ...

10월 26, 2024 · Jaejin Jang

2024 안동마라톤 하프코스 뒤늦은 후기

10월 6일(일) 안동마라톤 하프코스를 뛰고 왔습니다. 독서모임을 같이 하고 있는 형이랑 같이 참가했고 형의 어머니도 같이 출전, 형의 아버지께서 운전기사가 되어 3명의 컨디션을 위해 힘써주셨습니다. ...

10월 15, 2024 · Jaejin Jang

Gemma2-2b 사용해보기

참여하고 있는 구글 머신러닝 부트캠프에 google 계열의 모델을 개선하거나, 사용하여 앱을 만드는 과제가 있습니다. 저는 캠프에 참여한 목적자체가 제가 하고 있는 일부의 업무를 자동화시키기 위함이었어서 앱을 선택했고, 간단한 프로토타입을 만들어 봤습니다. 사실 pdf 파일에서 테이블을 추출하는 작업은 머신러닝에 맡기기보다는, 직접 형태를 보고 코딩하는 것이 더 나을 수도 있습니다. ...

10월 4, 2024 · Jaejin Jang

코세라) 신경망 및 딥러닝 - 얕은 신경망 - Planar data classification with one hidden layer (2)

생각보다 간단쓰 도함수 계산과정 좀 다시한번 봐야되겠네요. 너무 새롭네 Exercise 5 - compute_cost 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 # GRADED FUNCTION: compute_cost def compute_cost(A2, Y): """ Computes the cross-entropy cost given in equation (13) Arguments: A2 -- The sigmoid output of the second activation, of shape (1, number of examples) Y -- "true" labels vector of shape (1, number of examples) Returns: cost -- cross-entropy cost given equation (13) """ m = Y.shape[1] # number of examples # Compute the cross-entropy cost # (≈ 2 lines of code) # logprobs = ... # cost = ... # YOUR CODE STARTS HERE logprobs = np.multiply(np.log(A2), Y) + np.multiply(np.log(1-A2), 1-Y) cost = - 1 * np.sum(logprobs) / m # YOUR CODE ENDS HERE cost = float(np.squeeze(cost)) # makes sure cost is the dimension we expect. # E.g., turns [[17]] into 17 return cost Exercise 6 - backward_propagation 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 51 52 53 54 55 56 57 58 59 # GRADED FUNCTION: backward_propagation def backward_propagation(parameters, cache, X, Y): """ Implement the backward propagation using the instructions above. Arguments: parameters -- python dictionary containing our parameters cache -- a dictionary containing "Z1", "A1", "Z2" and "A2". X -- input data of shape (2, number of examples) Y -- "true" labels vector of shape (1, number of examples) Returns: grads -- python dictionary containing your gradients with respect to different parameters """ m = X.shape[1] # First, retrieve W1 and W2 from the dictionary "parameters". #(≈ 2 lines of code) # W1 = ... # W2 = ... # YOUR CODE STARTS HERE W1 = parameters["W1"] W2 = parameters["W2"] # YOUR CODE ENDS HERE # Retrieve also A1 and A2 from dictionary "cache". #(≈ 2 lines of code) # A1 = ... # A2 = ... # YOUR CODE STARTS HERE A1 = cache["A1"] A2 = cache["A2"] # YOUR CODE ENDS HERE # Backward propagation: calculate dW1, db1, dW2, db2. #(≈ 6 lines of code, corresponding to 6 equations on slide above) # dZ2 = ... # dW2 = ... # db2 = ... # dZ1 = ... # dW1 = ... # db1 = ... # YOUR CODE STARTS HERE dZ2 = A2 - Y dW2 = np.dot(dZ2, A1.T) / m db2 = np.sum(dZ2, axis=1, keepdims = True) / m dZ1 = np.dot(W2.T, dZ2) * (1 - np.power(A1, 2)) dW1 = np.dot(dZ1, X.T) / m db1 = np.sum(dZ1, axis=1, keepdims = True) / m # YOUR CODE ENDS HERE grads = {"dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2} return grads Exercise 7 - update_parameters 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 51 52 53 54 55 56 57 58 59 # GRADED FUNCTION: update_parameters def update_parameters(parameters, grads, learning_rate = 1.2): """ Updates parameters using the gradient descent update rule given above Arguments: parameters -- python dictionary containing your parameters grads -- python dictionary containing your gradients Returns: parameters -- python dictionary containing your updated parameters """ # Retrieve a copy of each parameter from the dictionary "parameters". Use copy.deepcopy(...) for W1 and W2 #(≈ 4 lines of code) # W1 = ... # b1 = ... # W2 = ... # b2 = ... # YOUR CODE STARTS HERE parameters_cp = copy.deepcopy(parameters) W1 = parameters_cp["W1"] b1 = parameters_cp["b1"] W2 = parameters_cp["W2"] b2 = parameters_cp["b2"] # YOUR CODE ENDS HERE # Retrieve each gradient from the dictionary "grads" #(≈ 4 lines of code) # dW1 = ... # db1 = ... # dW2 = ... # db2 = ... # YOUR CODE STARTS HERE dW1 = grads["dW1"] db1 = grads["db1"] dW2 = grads["dW2"] db2 = grads["db2"] # YOUR CODE ENDS HERE # Update rule for each parameter #(≈ 4 lines of code) # W1 = ... # b1 = ... # W2 = ... # b2 = ... # YOUR CODE STARTS HERE W1 = W1 - learning_rate * dW1 b1 = b1 - learning_rate * db1 W2 = W2 - learning_rate * dW2 b2 = b2 - learning_rate * db2 # YOUR CODE ENDS HERE parameters = {"W1": W1, "b1": b1, "W2": W2, "b2": b2} return parameters Exercise 8 - nn_model 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 51 52 53 54 55 # GRADED FUNCTION: nn_model def nn_model(X, Y, n_h, num_iterations = 10000, print_cost=False): """ Arguments: X -- dataset of shape (2, number of examples) Y -- labels of shape (1, number of examples) n_h -- size of the hidden layer num_iterations -- Number of iterations in gradient descent loop print_cost -- if True, print the cost every 1000 iterations Returns: parameters -- parameters learnt by the model. They can then be used to predict. """ np.random.seed(3) n_x = layer_sizes(X, Y)[0] n_y = layer_sizes(X, Y)[2] # Initialize parameters #(≈ 1 line of code) # parameters = ... # YOUR CODE STARTS HERE parameters = initialize_parameters(n_x, n_h, n_y) # YOUR CODE ENDS HERE # Loop (gradient descent) for i in range(0, num_iterations): #(≈ 4 lines of code) # Forward propagation. Inputs: "X, parameters". Outputs: "A2, cache". # A2, cache = ... # Cost function. Inputs: "A2, Y". Outputs: "cost". # cost = ... # Backpropagation. Inputs: "parameters, cache, X, Y". Outputs: "grads". # grads = ... # Gradient descent parameter update. Inputs: "parameters, grads". Outputs: "parameters". # parameters = ... # YOUR CODE STARTS HERE A2, cache = forward_propagation(X, parameters) cost = compute_cost(A2, Y) grads = backward_propagation(parameters, cache, X, Y) parameters = update_parameters(parameters, grads) # YOUR CODE ENDS HERE # Print the cost every 1000 iterations if print_cost and i % 1000 == 0: print ("Cost after iteration %i: %f" %(i, cost)) return parameters Exercise 9 - predict 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # GRADED FUNCTION: predict def predict(parameters, X): """ Using the learned parameters, predicts a class for each example in X Arguments: parameters -- python dictionary containing your parameters X -- input data of size (n_x, m) Returns predictions -- vector of predictions of our model (red: 0 / blue: 1) """ # Computes probabilities using forward propagation, and classifies to 0/1 using 0.5 as the threshold. #(≈ 2 lines of code) A2, cache = forward_propagation(X, parameters) predictions = np.round(A2) # YOUR CODE STARTS HERE # YOUR CODE ENDS HERE return predictions

8월 15, 2024 · Jaejin Jang

코세라) 신경망 및 딥러닝 - 얕은 신경망 - Planar data classification with one hidden layer

행렬간 차원의 개수와 수식이 쪼~금 이해가 되네요 Exercise 2 - layer_sizes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # GRADED FUNCTION: layer_sizes def layer_sizes(X, Y): """ Arguments: X -- input dataset of shape (input size, number of examples) Y -- labels of shape (output size, number of examples) Returns: n_x -- the size of the input layer n_h -- the size of the hidden layer n_y -- the size of the output layer """ #(≈ 3 lines of code) # n_x = ... # n_h = ... # n_y = ... # YOUR CODE STARTS HERE n_x = X.shape[0] n_h = 4 n_y = Y.shape[0] # YOUR CODE ENDS HERE return (n_x, n_h, n_y) Exercise 3 - initialize_parameters 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 # GRADED FUNCTION: initialize_parameters def initialize_parameters(n_x, n_h, n_y): """ Argument: n_x -- size of the input layer n_h -- size of the hidden layer n_y -- size of the output layer Returns: params -- python dictionary containing your parameters: W1 -- weight matrix of shape (n_h, n_x) b1 -- bias vector of shape (n_h, 1) W2 -- weight matrix of shape (n_y, n_h) b2 -- bias vector of shape (n_y, 1) """ #(≈ 4 lines of code) # W1 = ... # b1 = ... # W2 = ... # b2 = ... # YOUR CODE STARTS HERE W1 = np.random.randn(n_h, n_x) * 0.01 b1 = np.zeros((n_h, 1)) W2 = np.random.randn(n_y, n_h) * 0.01 b2 = np.zeros((n_y, 1)) # YOUR CODE ENDS HERE parameters = {"W1": W1, "b1": b1, "W2": W2, "b2": b2} return parameters Exercise 4 - forward_propagation 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 # GRADED FUNCTION:forward_propagation def forward_propagation(X, parameters): """ Argument: X -- input data of size (n_x, m) parameters -- python dictionary containing your parameters (output of initialization function) Returns: A2 -- The sigmoid output of the second activation cache -- a dictionary containing "Z1", "A1", "Z2" and "A2" """ # Retrieve each parameter from the dictionary "parameters" #(≈ 4 lines of code) # W1 = ... # b1 = ... # W2 = ... # b2 = ... # YOUR CODE STARTS HERE W1 = parameters["W1"] b1 = parameters["b1"] W2 = parameters["W2"] b2 = parameters["b2"] # YOUR CODE ENDS HERE # Implement Forward Propagation to calculate A2 (probabilities) # (≈ 4 lines of code) # Z1 = ... # A1 = ... # Z2 = ... # A2 = ... # YOUR CODE STARTS HERE Z1 = np.dot(W1, X) + b1 A1 = np.tanh(Z1) Z2 = np.dot(W2, A1) + b2 A2 = sigmoid(Z2) # YOUR CODE ENDS HERE assert(A2.shape == (1, X.shape[1])) cache = {"Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2} return A2, cache

8월 14, 2024 · Jaejin Jang

코세라) 신경망 및 딥러닝 - 파이썬과 벡터화 - 신경망 사고방식의 로지스틱 회귀 분석

단순하지만 기본이 되는 매우 중요한 과제입니다. 원래 기본이 가장 중요한 것 로지스틱 회귀 모델을 구축하여 고양이 이미지를 인식하는 시스템을 만드는 과제입니다. 기본적인 로지스틱 회귀 모델의 구현과 평가 방법을 익히며, 딥러닝의 기초적인 개념을 이해하고, 실질적인 머신러닝 모델을 만들어 봅니다. Exercise 1 shape를 통해 길이관련 정보에 접근할 수 있다는 것을 알아야 합니다. output을 보면 아시겠지만 트레이닝 이미지가 4차원 배열입니다.. 숫자로 적혀있으니 별 것 아닌것 같지만, 우리가 현실세계에서 4차원 공간을 마주할 일을 없습니다. 그것을 잘 표현해 놓은것이 인터스텔라의 테서렉트입니다(제 인생영화중에 하나라서 괜히 말함) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # YOUR CODE STARTS HERE m_train = train_set_x_orig.shape[0] m_test = test_set_x_orig.shape[0] num_px = train_set_x_orig.shape[1] # YOUR CODE ENDS HERE print ("Number of training examples: m_train = " + str(m_train)) print ("Number of testing examples: m_test = " + str(m_test)) print ("Height/Width of each image: num_px = " + str(num_px)) print ("Each image is of size: (" + str(num_px) + ", " + str(num_px) + ", 3)") print ("train_set_x shape: " + str(train_set_x_orig.shape)) print ("train_set_y shape: " + str(train_set_y.shape)) print ("test_set_x shape: " + str(test_set_x_orig.shape)) print ("test_set_y shape: " + str(test_set_y.shape)) ## output Number of training examples: m_train = 209 Number of testing examples: m_test = 50 Height/Width of each image: num_px = 64 Each image is of size: (64, 64, 3) train_set_x shape: (209, 64, 64, 3) train_set_y shape: (1, 209) test_set_x shape: (50, 64, 64, 3) test_set_y shape: (1, 50) Exercise 2 reshape에서 -1의 의미를 알아야 합니다. 하나의 인자만 -1로 넘길 수 있는데, -1인 부분은 나머지 값을 통해 추론하겠다라는 의미입니다. 1 2 train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T Exercise 3 - sigmoid 1 2 3 def sigmoid(z): s = 1/(1+np.exp(-z)) return s Exercise 4 - initialize_with_zeros 1 2 3 4 def initialize_with_zeros(dim): w = np.zeros((dim, 1)) b = 0.0 return w, b Exercise 5 - propagate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def propagate(w, b, X, Y): m = X.shape[1] A = cost = dw = db = cost = np.squeeze(np.array(cost)) grads = {"dw": dw, "db": db} return grads, cost Exercise 6 - optimize 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 def optimize(w, b, X, Y, num_iterations=100, learning_rate=0.009, print_cost=False): w = copy.deepcopy(w) b = copy.deepcopy(b) costs = [] for i in range(num_iterations): grads, cost = propagate(w, b, X, Y) dw = grads["dw"] db = grads["db"] w = w - learning_rate*dw b = b - learning_rate*db # Record the costs if i % 100 == 0: costs.append(cost) if print_cost: print ("Cost after iteration %i: %f" %(i, cost)) params = {"w": w, "b": b} grads = {"dw": dw, "db": db} return params, grads, costs Exercise 7 - predict 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def predict(w, b, X): m = X.shape[1] Y_prediction = np.zeros((1, m)) w = w.reshape(X.shape[0], 1) Z = np.dot(w.T, X) + b A = 1 / (1 + np.exp(-Z)) for i in range(A.shape[1]): if A[0, i] > 0.5 : Y_prediction[0,i] = 1 else: Y_prediction[0,i] = 0 return Y_prediction Exercise 8 - model 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 def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False): w, b = initialize_with_zeros(X_train.shape[0]) params, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, True) w = params["w"] b = params["b"] Y_prediction_test = predict(w, b, X_test) Y_prediction_train = predict(w, b, X_train) if print_cost: print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100)) print("test accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100)) d = {"costs": costs, "Y_prediction_test": Y_prediction_test, "Y_prediction_train" : Y_prediction_train, "w" : w, "b" : b, "learning_rate" : learning_rate, "num_iterations": num_iterations} return d

7월 27, 2024 · Jaejin Jang