-
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
1 parent
cd6b6d3
commit b6e9fcf
Showing
1 changed file
with
89 additions
and
0 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,89 @@ | ||
# 파이브 라인스 오브 코드 | ||
## 4. 타입 코드 처리하기 | ||
### 규칙: if 문에서 else 를 사용하지 말 것 | ||
- 프로그램에서 이해하지 못하는 타입인지를 검사하지 않는 한 if 문에서 else 를 사용하지 않는다. | ||
|
||
- `if-else` 를 사용하면 코드에서 결정이 내려지는 지점을 고정하게 된다. | ||
|
||
- 독립된 if 문은 검사로 간주하고, if-else 문은 의사 결정으로 간주한다. | ||
|
||
``` js | ||
// AS IS | ||
function average(ar: number[]) { | ||
if (size(ar) === 0) { | ||
throw new Error("Cannot take average of empty array"); | ||
} | ||
return sum(ar) / size(ar); | ||
} | ||
|
||
// TO BE | ||
function average(ar: number[]) { | ||
assertNotEmpty(ar); | ||
return sum(ar) / size(ar); | ||
} | ||
|
||
function assertNotEmpty(ar: number[]) { | ||
if (size(ar) === 0) { | ||
throw new Error("Cannot take average of empty array"); | ||
} | ||
} | ||
``` | ||
#### 스멜 | ||
- 이른 바인딩: if-else 같은 의사결정 동작은 컴파일 시 처리되어 애플리케이션에 고정되면 재컴파일 없이는 수정할 수 없다. | ||
- 늦은 바인딩: 코드가 실행되는 순간 동작이 결정됨 | ||
|
||
#### 의도 | ||
- if 는 흐름을 제어 -> 다음에 실행할 코드를 결정한다는 뜻 | ||
|
||
### 리펙터링: 클래스로 타입 코드 대체 | ||
- 열거형을 인터페이스로 변환하고 열거형의 값들을 클래스가 되도록 변환한다. | ||
- 해당 리펙터링 패턴은 자체적으로 많은 가치를 가지지 않지만, 추후 개선을 가능하기 한다. | ||
|
||
### 리펙터링: 클래스로 코드 이관하기 | ||
- 기능을 클래스로 옮기면서 클래스로 타입 코드 대체 패턴의 자연스러운 연장선 | ||
- 특정 값과 연결된 기능이 값에 해당하는 클래스로 이동하기 때문에 불변속성을 지역화 | ||
|
||
### 리펙터링: 메서드의 인라인화 | ||
- 프로그앰에서 더 이상 가독성에 도움이 되지 않는 메서드를 제거 | ||
- 단, 메서드를 인라인으,로 사용하는 것과는 다른 개념 | ||
|
||
- 메서드가 인라인화 하기 너무 복잡한가? | ||
-> 낮은 수준의 연산에 의존하여 가독성에 도움이 되는 경우에는 인라인화하지 않는다. | ||
|
||
### 리펙터링: 메서드 전문화 | ||
- 일반화하고 재사용하려는 본능적인 욕구가 있지만 그렇게 하면 책임이 흐려지고, 다양한 위치에서 코드를 호출할 수 있기 때문에 문제가 될 수 있음 | ||
- 전문화된 메서드는 더 적은 위치에서 호출되어 필요성이 없어지면 더 쉽게 제거 가능함 | ||
|
||
### 규칙: switch 를 사용하지 말것 | ||
- default 케이스가 없고 모든 case 에 반환값이 존재하는 경우에는 switch 를 사용하지 않는다. | ||
|
||
#### switch 의 문제점 | ||
|
||
- 컴파일러 입장에서 새로 추가한값의 처리에 대한 누락을 알 수 없다. | ||
- break 키워드 누락으로 인한 버그 | ||
|
||
#### 스멜 | ||
- switch 문은 값을 처리하는 방법에 초점, 클래스에 기능을 추가할때는 값이 상황을 처리하는 방법에 초점 | ||
- 컨텍스트에 초점을 맞춘다는 것은 불변속성을 전역화하는 것을 의미 | ||
|
||
#### 의도 | ||
- switch -> else if -> 클래스로 변환 | ||
|
||
- 인터페이스 대신 추상 클래스를 사용할 수 없을까? | ||
- 사용할 수 있다. 코드의 중복을 피할 수 있다. | ||
- 하지만 인터페이스를 사용하면 개발자가 능동적으로 무엇인가를 해야함. 즉, 누락으로 인한 오류를 방지할 수 있음 | ||
|
||
#### 규칙: 인터페이스에서만 상속받을 것 | ||
- 상속은 오직 인터페이스를 통해서만 받는다. | ||
|
||
- 추상 클래스를 사용하는 것은 일부 메서드의 기본 구현을 제공하고, 다른 메서드를 추상화 하기 위함 | ||
- 중복을 줄이고 코드의 줄을 줄이고자 할 경우 편리 | ||
- 하지만 추상 클래스의 코드 공유는 커플링을 유발하고, 기본 구현으로 인해 재정의가 필요한 메서드 인지 컴파일러를 통해 확인이 어려움 | ||
|
||
#### 스멜 | ||
> 상속보다는 컴포지션이 더 좋다 <<GoF의 디자인 패턴>> | ||
### 리팩터링: 삭제 후 컴파일하기 | ||
- 인터페이스에서 사용하지 않는 메서드를 제거하는 것 | ||
- 메서드를 삭제하고 컴파일러에서 허용하는지 확인하는 것 | ||
|