2.3 canRoll

- 테스트에 있는 중복 제거
2.3.1 canRoll

- 불필요한 코드 제거
3.1 gutterGame - add failing test

- score를 바로 호출하고 싶지만, 게임이 끝나야만 score함수를 호출할 수 있다.
- 게임을 끝내는 가장 간단한 방법은 gutter game이다.
3.2 gutterGame - make it pass
4.1 allOnes - add failing test

- next most simple and interesting test case
4.2 allOnes - make it pass
4.3 allOnes - prepare extract method
4.3.1 allOnes - extract method
4.3.2 allOnes - inline variables and move method position
5.1 oneSpare - add failing test

- gutter, allOne이 있으니 allTwo를 생각해 볼 수 있으나 이건 잘 동작할 것이다.
- 뻔히 동작할 것을 알 수 있는 테스트는 작성할 필요가 없다.
- allThree, allFour도 잘 동작할 것이다. 그런데 allFive는 그렇지 않다. spare가 있기 때문에.
- spare에 대한 테스트를 작성할 차례이다. 가장 간단한 spare는 어떤 경우가 있을까 ? one spare + gutter.
5.2 oneSpare - make it pass

- 근데 어떻게 해야 할지 모르겠다.
public void roll(int pins) {
    if(pins + lastPins == 10)
    ...
}
- 위와 같이 하려다 보니 이상하다. 플래그 변수, 정적 변수를 사용해야 하고…
- 이처럼 끔찍한 일을 해야 하는 경우가 생길때마 잠시 물러나야 한다.
- 뭔가 디자인이 잘 못된 것이다.
- 디자인 원칙이 위배된 것이 있다.
- 첫번째 원칙: 스코어를 계산하는 것을 의미하는 이름을 갖는 함수가 무엇인가 ?
- score 함수이다. 근데 실제로 score를 계산하는 함수는 roll 함수이다.
- 잘못된 책임 할당(misplaced responsibility)이 디자인 원칙, 잘못된 디자인 냄새이다.
- roll에선 각 roll을 저장하고, score에서 계산을 해야 한다.
- 어쩌지. refactoring. 근데 failing test가 있다. @Ignore 처리…
5.3 oneSpare - refactoring

- 이제 테스트가 수행되니 리팩토링하자.
- Roll을 배열에 저장하자.
- 이에 misplaced responsibility가 해소되었다.
6.1 oneSpare - add failing test
6.2 oneSpare - make it work by ignoring
6.3 oneSpare - refactoring

- frame을 도입하여 읽기 쉽게한다.
7.1 oneSpare - add failing test
7.2 oneSpare - make it pass
7.3 oneSpare - refactoring

- rename i to firstFrame
- 처음부터 firstFrame이라는 변수명을 찾은 것이 아니라 여러차례의 시도로 찾음
7.3.1 oneSpare - refactoring

- extract method isSpare
7.3.1 oneSpare - refactoring

- remove duplication