Skip to content

Commit

Permalink
11, 12
Browse files Browse the repository at this point in the history
  • Loading branch information
HanweeeeLee committed Jun 17, 2023
1 parent 4dc813d commit ef87271
Show file tree
Hide file tree
Showing 4 changed files with 406 additions and 0 deletions.
241 changes: 241 additions & 0 deletions Topic 09. 중복의 해악/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
# Topic 09. DRY: 중복의 해악
지식은 고정적이지 않음. 지식은 변화한다.
이런 불안정성은 유지 보수 모드에서 우리가 대부분의 시간을 쓸 거라는 뜻
이유가 무엇이건, 유지 보수는 별개의 활동이 아니며 전체 개발 과정의 일상적인 부분이다.
문제는 유지보수 과정에서 명세와 프로세스, 개발하는 프로그램에 지식을 중복해서 넣기 쉽다는 것이다. 그렇게 된다면 유지보수의 악몽이 시작될 것이다.
이렇게 안하려면 DRY(Don't Reapeat Yourself)원칙을 따라보자.

## DRY는 코드 밖에서도
DRY원칙에 적용되는 것들은 소스 복붙뿐 아니라 지식의 중복, 의도의 중복에 대한것도 포함이다. 똑같은 개념을 다른 곳 두군데에서 표현하면 안 된다는 뜻이다.

## 코드의 중복

```Ruby
def prit_balance(account)
printf "Debites: %10.2f\n", account.debits
printf "Credits: %10.2f\n", account.credits
if account.fees < 0
printf "Fees: %10.2f-\n", account.fees
else
printf "Fees: %10.2f\n", account.fees
end
printf " ---------\n"
if account.balance < 0
printf "Balance: %10.2f-\n", account.balance
else
printf "Balance: %10.2f\n", account.balance
end
end

```
> 중복이 많이 보인다. 개선해보자.
```Ruby

def format_amount(value)
result = sprintf("%10.2f", value.abs)
if value < 0
result + "-"
else
result + " "
end
end

def prit_balance(account)
printf "Debites: %10.2f\n", account.debits
printf "Credits: %10.2f\n", account.credits
# if account.fees < 0
# printf "Fees: %10.2f-\n", account.fees
# else
# printf "Fees: %10.2f\n", account.fees
# end

printf "Fees: %s\n", format_amount(account.fees)


printf " ---------\n"
# if account.balance < 0
# printf "Balance: %10.2f-\n", account.balance
# else
# printf "Balance: %10.2f\n", account.balance
# end

printf "Balance: %s\n", format_amount(account.balance)
end

```

->

```Ruby

def format_amount(value)
result = sprintf("10.2f", value.abs)
if value < 0
result + "-"
else
result + " "
end
end

def prit_balance(account)
# printf "Debites: %10.2f\n", account.debits
printf "Debites: %s\n", format_amount(account.debits)
# printf "Credits: %10.2f\n", account.credits
printf "Credits: %s\n", format_amount(account.credits)

printf "Fees: %s\n", format_amount(account.fees)
printf " ---------\n"
printf "Balance: %s\n", format_amount(account.balance)
end

```

->

```Ruby

def format_amount(value)
result = sprintf("10.2f", value.abs)
if value < 0
result + "-"
else
result + " "
end
end

def print_line(label, value) # 추가
printf "%-9s%s\n", label, value
end

def report_line(label, amount) # 추가
print_line(label + ":", format_amount(amount))
end

def prit_balance(account)
# printf "Debites: %s\n", format_amount(account.debits)
report_line("Debites", account.debits)
# printf "Credits: %s\n", format_amount(account.credits)
report_line("Credits", account.credits)
# printf "Fees: %s\n", format_amount(account.fees)
report_line("Fees", account.fees)
# printf " ---------\n"
# printf "Balance: %s\n", format_amount(account.balance)
report_line("Balance", account.balance)
end

```

## 모든 코드 중복이 지식의 중복은 아니다.

```Ruby
def validate_age(value):
validate_type(value, :integer)
validate_min_integer(value, 1)

def validate_quantity(value):
validate_type(value, :integer)
validate_min_integer(value, 1)
```
> 두 함수가 동일하기 때문에 DRY 위반? ㅡㄹ렸다. 코드는 동일하지만 두 함수가 표현하는 지식은 다르다. 두 함수는 각각 서로 다른 것을 검증하고 있지만, 우연히 규칙이 같은 것뿐이다. 이것은 우연이지 중복이 아니다.

## 문서화 중복
왜인지 모르겠지만 모든 함수에 주석을 달아야 한다는 미신이 생겨났다.
그런 사람들은 이런 코드를 작성한다.

```Ruby
# 계좌의 수수료를 계산한다.
#
# * 반려된 수표 하나당 $20
# * 계좌가 3일 넘게 마이너스이면 하루에 $10 부과
# * 평균 잔고가 $2,000보다 높으면 수수료 50% 감면

def fees(a)
f = 0
if a.returned_check_count > 0
f += 20 * a.returned_check_count
end
if a.overdraft_days > 3
f += 10 * a.overdraft_days
end
if a.average_balance > 2_000
f /= 2
end
f
end
```
이 함수는 중복되어있다. 한 번은 코드로, 또 한 번은 주석으로.
클라이언트가 수수료를 바꾸면 우리는 두 군데를 함께 고쳐야 한다. 시간이 지남에 따라 주석과 코드의 내용이 서로 어긋나게 될 거라고 거의 확실히 장담할 수 있다.
함수 이름과 코드로 의도를 파악하도록 만들자

## 데이터의 DRY 위반
```Java

class Line {
Point start;
Point end;
double length;
}

```
시작과 끝이 있으면 길이도 있다. 길이는 계산되는 필드로 만드는 편이 낫다.

```Java

class Line {
Point start;
Point end;
double length() { return start.distanceTo(end); }
}

```
요렇게!

```Java

class Line {
private double length;
private Point start;
private Point end;

public Line(Point start, Point end) {
this.start = start;
throw .end = end;
calculateLength();
}

// public
void setStart(Point p) { this.start = p ; calculateLength() }
void setEnd(Point p) { this.end = p ; calculateLength() }

Point getStart() { return this.start; }
Point getEnd() { return this.end; }

double getLength() { return this.length; }

private void calculateLength() {
this.length = start.distanceTo(end);
}

}

```

## 표현상의 중복
서드파티를 연동하면 한쪽에서 수정하면 다른 한쪽이 망가질 것이다.
이런 중복을 아예 피할 수는 없지만 다소 완화할 수는 있다.

### 내부 API에서 생기는 중복
언어나 기술에 중립적인 형식으로 내부 API를 정의할 수 있는 도구를 찾아보아라. 이런 도구는 일반적으로 문서와 Mock API, 기능 테스트를 생성해주고, API 클라이언트도 여러 가지 언어로 생성해준다.

### 외부 API에서 생기는 중복
공개 API를 OpenAPI 같은 형식으로 엄밀하게 문서화하는 경우가 많음. API도구를 사용해보자(포스트맨 같은거 말하는듯?)

### 데이터 저장소와의 중복
많은 데이터 저장소가 데이터 스키마 분석 기능을 제공한다. 이런 기능을 이용하면 데이터 저장소와 코드 간의 중복을 많이 제거할 수 있다.


## 개발자 간의 중복
똑같은 일을 하는 코드가 우연히 중복으로 추가 될 수 있음. 알아차릭기 힘들다.
일일 스크럼을 하든 프로젝트의 사서를 지정하든 해라.. 코드리뷰도 좋음.

72 changes: 72 additions & 0 deletions Topic 10. 직교성/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Topic 10. 직교성


## 직교성이란
독립성이나, 결합도 줄이기를 의미함.

## 직교성의 장점
컴포넌트들이 각기 격리 되어 있으면 어느 하나를 바꿀 떄 나머지 것들을 걱정하지 않아도 된다.
직교적인 시스템을 작성하면 두 가지 큰 장점이 있다. 바로 생산성 향상과 리스크 감소다.

### 생산성 향상
- 변화를 국소화해서 개발 시간과 테스트 시간이 줄어든다.
- 재사용을 촉진한다
- 생산성 향상

### 리스크 감소
- 감염된 코드가 격리되어 있다.
- 시스템이 잘 깨지지 않는다.
- 테스트를 설계하고 실행하기 쉽다.
- 업체나, 제품, 플랫폼에 덜 종속된다.

## 설계
시스템은 서로 협력하는 모듈의 집합으로 구성되어야 하고, 각 모듈은 다른 부분과 독립적인 기능을 구현해야 한다.
계층 구조는 직교적 시스템을 설계하는 강력한 방법이다. 각 계층은 자기 바로 밑에 있는 계층이 제공하는 추상화만을 사용하기 때문에, 다른 코드에 영향을 끼치지 않으면서 기반 구현들을 변경할 수 있게 되어 유연성이 높아짐
![KakaoTalk_Photo_2023-06-15-16-17-12](https://github.com/WBBookStudy/ProgramProgrammingProgrammer/assets/60125719/0a64db9a-07a0-4c6b-bfe8-7591c9fe7756)
설계가 직교적인지 확인하는 손쉬운 방법은 컴포넌트들을 나누었을 때 스스로에게 물어보아라. '특정 기능에 대한 요구 사항을 대폭 변경해야 하는 경우 몇 개의 모듈이 영향을 받는가?' 정답은 하나여야 함.

## 툴킷과 라이브러리
외부에서 만든 툴킷이나 라이브러리를 도입할 때 시스템의 직교성을 해치지 않는지 주의 깊게 살펴보아라.

## 코딩
코드를 작성할 때마다 애플리케이션의 직교성을 떨어트릴 위험을 감수하는 셈이다.
직교성을 유지하기 위해 사용할 수 있는 몇 가지 기법이 있다.

- 코드의 결합도를 줄여라
- 전역 데이터를 피하라
- 유사한 함수를 피하라

자신이 작성하는 코드를 항상 비판적으로 바라보는 습관을 길러라. 기회가 있을 때마다 코드의 구조와 직교성을 개선하기 위해 노력하라.

## 테스트
직교적으로 설계하고 구현한 시스템은 테스트하기 더 쉽다. 시스템 컴포넌트 간의 상호 작용이 형식을 잘 갖추고 있고 제한적이기 때문에 시스템 테스트 중 많은 부분을 개별 모듈 수준에서 수행할 수 있다.
단위 테스트가 나머지 시스템의 많은 부분들을 불러와야해서 힘들다면 결합도를 충분히 줄이지 못했다는 뜻이다.
버그 수정을 통해 어떤 한 부분만 수정하면 되었는가? 또 다른 버그가 생기지는 않았는가? 이 질문들에 제대로 답하려면 자동화도 적용을 해야한다.

## 문서화
놀랍게도 직교성은 문서에도 적용할 수 있다.
정말 직교적인 문서라면 내용 변화 없이 모양새를 완전히 바꿀 수 있다.

## 직교적으로 살아가기
직교성은 DRY 원칙과도 밀접한 관계가 있다. 당연한 말이겠지만 DRY원칙으로 무장하고 직교성 원칙을 충실히 적용한다면 개발하고 있는 시스템이 더 유연하고 이해하기 쉬워질 것이다. 디버깅, 테스트, 유지보수도 쉬워질 것이다.





















34 changes: 34 additions & 0 deletions Topic 11. 가역성/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Topic 11. 가역성
엔지니어는 문제를 풀 때 단순한 하나의 해결책을 좋아하지만 세상엔 영원한 것은 없다.
중요한 결정이 많이 내려졌을 즈음엔 목표가 너무 작아져서 목표가 움직이거나, 바람의 방향이 바뀌거나, 도쿄의 나비가 날갯짓을 한다면 여러분의 겨냥은 빗나갈 것이다.


## 가역성
이 책의 많은 주제는 유연하고 적용 가능한 소프트웨어를 만드는것. DRY원칙, 결합도 줄이기, 외부 설정 사용하기 등이 그런 예시
되돌릴 수 없는 결정을 줄이자. 왜냐하면 우리가 프로젝트 초기에 늘 최선의 결정을 내리지 못하기 때문.

## 유연한 아키텍처
아키텍처, 배포, 외부 제품과의 통합 영역을 유연하기 유지하는 데에 관심을 기울이자.
우리가 할 수 있는건 바꾸기 쉽게 만드는 것이다. 외부의 API를 우리가 만든 추상화 계층으로 숨겨라. 우리의 코드를 여러 컴포넌트로 쪼개라. 결국에는 하나의 거대한 서버에 배포하게 되더라도, 이 방식이 거대한 단일 모듈 어플리케이션을 가져다 쪼개는 것보다 훨씬 쉽다. 그리고 **유행을 좇지 말라.** 누구도 어떤 미래가 펼쳐질지 알 수 없으며, 우리는 특히 더 그렇다.






















Loading

0 comments on commit ef87271

Please sign in to comment.