# TDD(Test Driven Development)
> 분석 기술이자 설계 기술입니다. 프로그래밍 의사 결정과 피드백 사이의 간극을 의식하여 제어할 수 있습니다.

**TDD는 분석과 설계를 잘 해야 한다.**
* TDD = Test First Development + Refactoring
* TDD는 테스트를 먼저 개발하는것이 주된 목적이 아니고 리팩토링이 주된 목적이다.
* 짧고 작은 단위의 설계를 지속하여 개발하는 방법.
* 한번에 모든걸 만들지 않고 작은 단위를 만들어 간다.
---
* TDD는 한번에 한가지 만 고민하여 기능을 우선 개발한다.
* 이후 개발된 기능을 바탕으로 refactoring을 진행한다.
* 이때 테스트 코드나 테스트 케이스는 추가되거나 수정되지 않아야 한다.
---
* 큰단위를 작은 단위로 나눠 빠르게 실패.
* 피드백을 통해 지속적 개선
* 달성하기 힘들 것으로 생각하는 일에 도전할 수 있는 용기
* 의식적인 연습이 필요하다.
  * 학습테스트 
  * 단위테스트

<br>

### 코드 컨벤션을 지켜라
다른 개발자와 협업이나 미래의 나를 위해서라도.  

공백 라인을 의미있게 사용해라.  
공백 라인이 메소드의 기능을 나누게 되는 기준이 된다.   
추후 리펙토링 시 메소드 기준으로 기능이 나뉜다는것을 알고 공백기준으로 메소드 리펙토링이 가능하다.  

### 네이밍
객체지향 생활 체조 규칙 5 : 축약하지 말라.  
적당한 길이의 이름을 찾는데 집중해라.  

인스턴스 변수의 중복을 줄이고, 개수를 최소화 해라.  
데이터를 꺼내려고 하지않고 메시지를 던져라  
비지니스 로직과 ui로직의 분리.  
테스트 가능한 코드와 불가능한 코드가 섞여 있으면 분리를 해야 한다.  
어느 부분을 테스트 할 것인가 ?  
경계값을 기준으로 테스트해야 한다.  
Test Fixture를 위해서 생성자를 추가하는것이 옳은 일인가 ?   
도메인이 DTO역할을 하는 경우라면 생성자를 추가하는것이 허용된다.   
해당 경우에는 허용하는 것으로 ..   
역할이 여러개이면 클래스 분리.  
private메소드가 많아지면 테스트를 해야 하는것인가 ?   
Private 메소드가 중요한 비지니스 역할을 한다면 새로운 클래스로 분리 되어야 한다.   
분리 된다면 다른 클래스에서 접근 가능한 메소드가 되기때문에 테스트가 가능하다.  

### TDD 
이번주 부터는 메소드 분리가 아닌 클래스 분리를 연습 하자  
모든 원시값과 문자열을 포장한다.   
일급 콜렉션을 쓴다.  
생성자를 중복해 정의할 때는 정적 팩토리 메소드를 사용한다.  

tdd는 리팩토링이 가장 중요하다.  
테스트와 production code를 추가할 때 마다 리팩토링을 해야한다.  
한번에 리팩토링을 하지 않고 테스트 케이스가 추가 될 때 마다 리팩토링을 하는 연습을 해야 한다.  
todo리스트를 제대로 만드는것이 tdd를 잘하는 방법이다.  
설게를 안하는것이 아니고 초반에 대략적인 설계가 필요하다.  
초반 설계시 테스트 가능한 부분과 힘든 부분까지 설계를 한다면 설계를 잘한 것이다.  

tdd 시작시 인풋과 아웃풋을 결정해야 한다.  
Getter 를 쓰는순간 없애려고 노력해라 (상태를 가진 데이터를 꺼내는것보다 객체에 메시지를 보내서 일을 시켜라)  

접근 제어자를 잘 사용해서 클래스 및 메소드의 접근 범위를 한정하는것도 도메인을 지키는 방법이다.   특히 default 접근 제어자는 도메인을 지키는 좋은 방법중 하나이다.  

토이 프로젝트에선 최대한 조건을 강제해라  
인덴트 1, 인스턴스 변수 2개 등의 극한의 조건을 걸어라.  

---
### Q&A
Void method 는 검증하는것만으로도 의미가 존재 하는지 ?  
-> 존재한다.  
Void method 내부에서도 인풋과 아웃풋이 있는 부분을 분리할 수 있을것이다. 그부분을 메소드로 분리해서 테스트 가능하다.  

### 유효성 검사
도메인은 반드시 유효성 검사를 해야 하는것이 맞다.   
그렇다고 controller나 다른 레이어에서 유효성검사를 안해도 된다는것은 아니다.  

<br>

* tdd 사이클이 익숙해질때 까지 반복적으로 연습해야 한다.
	* 가장 자신있는 언어로 반복 연습하는것을 추천.
	* 힘들고 지칠땐 주제를 바꿔서 해보는것이 좋다.

### 시작하기
* 요구사항 분석을 통한 기능 목록 작성
* 객체설계를 통해 어느 부분 부터 구현할 지 생각하는것이 우선이다.

* 기능목록
	* 주제에 대해서 가장 일반적인 기능들을 다 적어보자.
	* 점차 작은 단위의 기능들도 정의

* TDD로 구현할 기능 찾기
	* 큰 부분을 작게 자르는 연습을 해야한다.

* 인풋과 아웃풋이 있는 케이스가 테스트 하기 쉽다.
* 메서드 하나에 모든 로직이 들어가 있으면 객체지향적인 구조보다 절차지향적 구조로 변질되게 된다.

* 리팩토링, 어디서 부터 시작할까 ?
	1. 첫밴쨰는 메소드 분리부터 시작. (Naming Rename도 해야한다.)
		1. 메소드가 한가지 일만 잘하도록 구현한다.
			* 한가지 일만 하기 위해 메소드 라인을 제약하는것도 좋은 방법이다.
	2. Indent를 줄이자.
		1. Else 예약어를 쓰지 않는다.
	3. 클래스를 분리하자.
		1. 원시값과 문자열을 포장
		2. 일급 콜렉션을 사용한다.
		3. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않기.
		4. 메소드 인자수를 제한한다. 2개까지만 허용한다.
			1. 3개는 고민을 많이 하고, 4개는 절대 안된다.
			2. 비슷한 속성을 가진 인자수를 클래스로 만들어 보자. 
				1. 속성과 라이프 사이클이 동일하면 쉽게 판단할 수 있다.
* private method를 분리해서 단위테스트 해야하는 것이 아닌가 ? 라는 의구심
	* private method를 다른 클래스로 만들어 public으로 open하는게 더 나은 구조는 아닐까 생각해보자.
* 새로운 클래스가 생성될때 테스트부터 만들어 보자.

* 상속(is-a) 조합(has-a)
	* 일급 collection을 구현할 때 접근 방법으로 상속과 조합 방법으로 구현 가능
	* 객체의 중복(Lotto와 WinningLotto)를 제거 할 때 상속과 조합 방법으로 구현 가능

* 상속은 의도하지 않은 인터페이스가 외부에 노출될 수 있다.  
반면 조합을 사용하면 외부에 오픈할 인터페이스를 정의할 수 있다.

* **상속과 조합 중 어떤것이 좋을까 ?**
	* 상속 보단 객체 조합을 사용해라.
	* 코드의 재사용성 측면에선 상속이 유리. 유연성 측면에선 조합이 유리.
		* 변화에 빠르게 대응하는 것이 점점 더 중요, 현재는 재사용성 보다 유연성이 훨씬 더 중요하다.
		* 확실하게 경험을 하는것이 좋다 !
* 생성자 대신 정적 팩토리 메소드 사용.
	* 생성자의 수가 늘어날수록 클래스를 사용하기 위한 유연성은 높아진다.
* 가변객체보단 불변 객체를 사용해라.
* 불변 객체 만들기
	* 객체의 상태를 변경하는 메소드를 제공하지 않는다.
	* 클래스를 확장 할 수 없도록 한다. (Public final class)
	* 모든 필드를 final로 선언한다.
		* 내부에 collection이 있다면 collection도 불변인지 확인해야 한다.
	* 모든 필드를 private으로 선언한다.
* immutable object 가 좋은것은 알겠는데, 인스턴스가 많이 생성되어 성능이 떨어지지 않을까 ?
	* 캐싱을 적용해 인스턴스 생성을 최소화 할 수 있는 방법이 있는지 검토
		* 캐싱은 일반적으로 Map(key - value) 형식을 가장 많이 사용된다.

성능외에도
유지보수하기 좋은 코드, 읽기 좋은 코드, 유연한 코드, 버그 발생 가능성이 낮은 코드 와 같이 다양한 측면을 고려하면서  프로그래밍 하는습관을 가지자

### 경험해야할 학습 목표 - 사다리 타기
	* TDD, 객체 지향 프로그래밍 연습
	* 인터페이스를 추출하여 프로그래밍 하는 연습을 한다.
	* stream, lambda를 사용해 프로그래밍하는 것을 연습.

### 경험할 객체 지향 생활 체조 원칙
* 한줄에 점 하나만  찍는다.
	* Clean Code 가이드의 디미터 법칙을 지키는 것을 의미.
* 모든 엔티티는 작게
* 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
* getter / setter / property를 쓰지 않는다.

### 함수형 프로그래밍
* 함수형 프로그래밍은 input과 output이 항상 존재 하기 때문에 test하기 쉽다.

* 클래스 기반 함수를 모으로 메소드 레벨에서 함수형 프로그래밍에 맞게 설계 ?
* 람다를 쓰는게 중요한게 아니고 변경 가능성이 높은 부분을 인터페이스로 추출 할 수 있는지가 중요하다.

<br>

# 4주차
* 점진적 리팩토링
	* 기존의 테스트가 깨지지 않는 선에서 리팩토링 하기
	* 컴파일 에러가 발생하면 안된다.
* 일반적 상황
	* 메소드에 인자가 추가되었다.
	* 인스턴스 변수 타입이 변경되었다. 
		* -> 컴파일 에러가 발생 , 에러 해결 
* 위 방식 대로 리팩토링 하면 긍정적인 측면 보다. 부정적인 측면이 생길 수 있다.

* 우리가 연습해야할 리팩토링은 ?
	* 메소드에 인자가 추가 되는 경우
		* 메소드를 그대로 복사하여 메소드 이름을 임시로 변경
		* 임시 메소드를 하나씩 실제 사용한 메소드와 변경
		* 더이상 이전 메소드가 존재하지 않으면, 이전 메소드를 제거 후 이름 변경
	* 인스턴스 변수의 타입이 변경되는 경우
		* 새로운 인스턴스 변수 추가
		* String to Integer로 변경 시 일시적으로 두개 타입을 도시에 사용
		* 두개 변수에 동시에 데이터를 넣고 리팩토링

* 점진적 리팩토링 - TDD 에 대한 감이 생길때 시작
	* 1단계 - 메소드를 다른 클래스로 이동
	* 2단계 - 메소드에 인자 타입이나, 반환 타입이 변경 시
	* 3단계 - 인스턴스 변수 타입이 변경되는 경우
		* 데이터의 중복을 만든다. (임시 변수를 만들고, 메소드에 인자가 추가되는 경우와 같이 점차 변경해나간다.)

* 리팩토링은 시간 날때마다 진행하는것이다. 

* 객체지향 설계 및 구현 접근 방식은 ?
	* Bottom Up 설계 및 구현
		* 구현에 초점을 맞추어 일단 구현 후 지속적 리팩토링을 통해 역할,책임,협력을 찾아 나간다.
	* Top Down 구현 및 설계
		* 책임에 초점을 맞추어 전체적인 설계 후 구현
* 책임 주도 설계
	* 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계
		* 클래스를 먼저 설계하는것이 아니다.
* 책임이란 ?
	* 책임이란 객체가 유지해야할 정보와 수행해야할 행동
	* 즉 객체가 `무엇을 알고있는가` 와 `무엇을 할 수 있는가`로 구성된다.
* 역할을 다른것으로 교체할 수있는 책임의 집합이다.
* 테스트 하기 쉬운 코드가 유연한 코드는 아니지만 연습하다 보면 유연한 코드가 될 수 있다.
* 유연한 설계를 지향한다면 컴파일타임 의존성을 런타임 의존성으로 대체한다.
	* 의존성을 주입 한다.
* 런타임 의존성으로 대체하다보면 테스트하기 쉬운 설계가 가능해진다.
* 테스트하기 쉬운 설계를 지향하다보면 유연한 설계가 가능해지는 경험을 종종 할 수 있다.

* 책임 주도 설계가 진정한 대안인가 ?
	* 책임 주도 설계에 익숙해지기 위해선, 부단한 노력과 시간이 필요.
	* 책임 관점에서 사고하기 위해선 부단한 노력과 학습이 필요하다.
	* 빠르게 구현 후 지속적 리팩토링
	* TDD 사이클을 반복해 설계의 품질을 높힌다.
		* 리팩토링 시 객체지향 설계 체조원친, 클린코드 설계 원칙을 지키면서..

<br>

### 사다리 타기 tdd 구현
* Out - in 접근 방식 vs in.- out 접근 방식
* TDD 로 구현하기에는 in.- out 방식이 더 적합하다.
	* 가장 작은 단위의.객체부터 기능을 추가하면서 개발한다.
	* 도메인 설계에서 가장 마지막 객체(의존관계가 없는)
	* 가장 작은 단위의 객체가 구현되었으면, 객체를 더 작게 나눌수 없을까 고민
	* 가장 작은 단위의 객체가 새롭게 만들어 졌으면 다시 고민
		* 위와 같은 사이클을 계속하여 진행

* 책임주도설계로 사다리타기 재설계
	* 책임주도설계 == 인터페이스 주도 설계
		* 사다리 초기화(생성)
		* 사다리 실행
		* 사다리 결과 구하기
	* 메시지를 먼저 결정하면 내부 상태가 어떻게 도출될지는 자연스럽게 정해진다.
	* 책임 (객체가 해야할 행동, 메시지)를 먼저 정해보는것.

* 패키지들 간의 의존성은 단방향으로 만들어야 한다.
	* 추후에 큰변화 (분리) 할때 편리하다.
	* sonarqube와 같은 정적 분석 도구를 활용해 cyclic dependency를 찾아준다.

* 서비스 로직은 어디에 구현하는것이좋을까 ?
	* 일급 콜렉션을 쓴다.
	* 3개 이상의 인스턴스 변수를 사용하지 않는다.
	* 묻지 말고 시켜라. (데이터를 꺼내지말고 메시지를 던져라)
	* 상태 변경의 주도권은 외부에 있지 않고 도메인이 가지고 있어야 한다.

* 도메인 설계, 구현 반복
	* 요구사항을 분석후 도메인 설계.
	* 한번에 완벽한 설계를 하겠다는 욕심을 버려라.
		* 반복적인 설계와 구현을 통해 도메인에 대한 이해도를 높여야 한다.
		* 도메인에 대한 이해도가 높아야 추상화 수준도 높아진다.