software development #2: test-driven development

63
Combacsa’s SPARCS Web Seminar

Upload: britanney-petty

Post on 03-Jan-2016

103 views

Category:

Documents


3 download

DESCRIPTION

Combacsa’s SPARCS Web Seminar. Software development #2: Test-Driven Development. Test-Driven Development. Test-Driven Development. Agile Family (of course!) Test Code 작성으로부터 프로그램 개발이 진행되게 하는 방법론 . Two major philosophy 코딩을 시작하기에 앞서 , 실패하는 , 자동화된 테스트 코드 부터 작성하라 . 중복 을 제거 하라. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Software development #2: Test-Driven Development

Combacsa’s SPARCS Web Seminar

Page 2: Software development #2: Test-Driven Development

Test-Driven

Development

Page 3: Software development #2: Test-Driven Development

Test-Driven Development

Agile Family (of course!)

Test Code 작성으로부터프로그램 개발이 진행되게 하는 방법론 .

Two major philosophy 코딩을 시작하기에 앞서 ,

실패하는 , 자동화된 테스트 코드부터 작성하라 .

중복을 제거하라 .

Page 4: Software development #2: Test-Driven Development

Test Code 의 역할 ?

Test Code 는 보조 수단이다 프로그램 개발에 필수적인 요소

문서 설계 개발 실력 디버깅 능력

Test Code 는 조금 더 안심할 수 있도록 할 뿐 프로그램 개발의 필수 요소라고 볼 수 없다

Page 5: Software development #2: Test-Driven Development

TDD 에서 Test Code 의 역할 ! Test Code 는 필수적이다 !

Working Software 의 정의 “ 올바르게” 동작하는 프로그램 “ 올바르다” 의 정의는 어떻게 내리는가 ?

그때 그때 실행해 보면서 ? No, 확고하게 설계한 Test Code 를 실행해서 !

Test Code 작성만으로도 대형 프로젝트가 얼마든지 진행될 수 있다 !

Page 6: Software development #2: Test-Driven Development

Test Code 작성은 프로그램 개발의 보조수단일 뿐이다

Test 는 프로그램이당연히 통과해야 하는 것

Page 7: Software development #2: Test-Driven Development

TDD Rhythm in 5 Steps

Add a new TEST

Run all TESTs, and check there is a FAILURE

Slightly modify CODE

Run all TESTs, and check everything SUCCESS

Eliminate DUPLICATION by REFACTORING

Page 8: Software development #2: Test-Driven Development

TDD 에 따른 프로젝트의 삶

고객과 함께 TO-DO List 를 작성한다

리스트에서 할 일 하나을 고른다 TDD Rhythm 을 타면서 그 일을 처리한다

중간에 새로운 일이 생겨도 지금 처리중인 일에만집중하고 , 새로 생긴 일은 까먹지 않도록단지 TO-DO List 에 올리기만 한다

TO-DO List 가 빌 때까지 반복한다

프로그램 개발이 끝난다

Page 9: Software development #2: Test-Driven Development

TO-DO LIST할일 1할일 2할일 n …

할일 i

TEST Code for 할일 i

TEST Failure

Code for 할일 i

TEST SUCCESS

Refactored Code for 할일 i

TEST still SUCCESS

Page 10: Software development #2: Test-Driven Development

TDD Terminology

Red bar period Period when one or more tests fail 테스트 중 하나라도 통과하지 못한다

Green bar period Period when entire tests success 모든 테스트를 통과한다

개발 진행 = 새로운 빨간막대 파란막대

Page 11: Software development #2: Test-Driven Development

Let’s see how it really works.

Page 12: Software development #2: Test-Driven Development

제한점

어디까지나 TDD 를 “ 보여주기” 위한 것 TDD 를 진행하면서 일어날 수 있는 다양한

상황들을 위한 작위적인 예제임을 잊지 말자

JUnit Framework 를 사용하여 Java 로 코딩 Java 를 모르는 사람은 따라해보긴 힘들겠다 Java 를 알면 알아서 프로젝트 생성 / 파일

추가 잘 하고 따라해보길 바람 귀찮아서 Eclipse 스크린샷은 안 뜨겠음

Page 13: Software development #2: Test-Driven Development

Kent Beck’s Example

Project Bank Account 은행의 사용자 계좌 관리 프로그램을

개발하자 고객은 다음과 같은 사항을 요구한다

서로 다른 통화간에 덧셈이 가능해야 함 계좌에 있는 돈을 특정 배로 늘릴 수 있어야 함 Blah Blah Yada Yada …

첫단계 TO-DO List 부터 작성하자 .

Page 14: Software development #2: Test-Driven Development

TO-DO List 의 작성법

각각의 기능을 최대한 분해할 것 새로운 기능은 최소한의 Test 로

검증가능해야 !

때때로 TO-DO List 에서 제거할 일도 있다 다른 일을 처리하면서 자연스레 해결되는 경

우 .

Page 15: Software development #2: Test-Driven Development

TO-DO List 작성의 실제

고객 요구 조건 (Recall) 서로 다른 통화간에 덧셈이 가능해야 함 계좌에 있는 돈을 특정 배로 늘릴 수 있어야 함 두 계좌에 있는 돈이 동일함을 확인해야 함

기능만 뽑아내어 다시 써보자 ! $5 + 10YEN = $6 ( 환율이 1:10 일 때 ) $5 x 2 = $10 $5 = $5 ( 서로 다른 계좌 )

Page 16: Software development #2: Test-Driven Development

할일 고르기

원칙 다른 일보다 먼저 진행될 수 있는 것부터 다른 일보다 먼저 진행되어야 하는 것부터 좀더 쉽고 단순한 일부터

TODO List Recall $5 + 10YEN = $6 ( 환율이 1:10 일 때 ) $5 x 2 = $10 한 계좌에 대한 것 . 너로

정했다 $5 = $5 ( 서로 다른 계좌 )

Page 17: Software development #2: Test-Driven Development

Test Code 설계

Test Code 를 작성하며 결정되는 것들 함수 / 클래스의 이름과 파라메터 각 함수 / 클래스의 예상되는 동작

public void testMultiplication() {Dollar five = new Dollar(5);five.times(2);assertEquals(10,

five.amount);}

Page 18: Software development #2: Test-Driven Development

Test 실행

결과 확인 테스트 실패 : 컴파일조차 되지 않는다 .

Dollar 라는 클래스가 정의되지 않음

실패에 대한 대처법 원인을 파악하고 가장 간단한 것부터 해결한다

지금은 Dollar 클래스를 정의하면 충분하겠다 times 메소드와 amount 필드가 있어야겠다

어떻게든 이 테스트 코드를 통과시킬 수 없다면 다른 할일부터 해결하는 것이 나을지도 모른다

Page 19: Software development #2: Test-Driven Development

Dollar 클래스 설계

Public class Dollar {

int amount;

public Dollar(int amount) {

}

void times(int multiplier) {

}

}

Page 20: Software development #2: Test-Driven Development

Test 실행

결과 확인 assertEquals(10, five.amount);

결과가 0 이 나오고 있다

assertEquals(A, B) 메소드 A 의 값과 B 의 값이 일치할 때 통과하고 ,

일치하지 않을 때 실패하는 메소드이다 five 객체의 amount 변수의 값이 10 이

아니어서 통과하지 못한 것이다

Page 21: Software development #2: Test-Driven Development

상념에 대한 적절한 대처

상념 1 : amount 멤버 변수는 개인 정보이니private 로 지정되었어야 하지 않나 ? 대처 1 : TODO 리스트에 다음을 추가한다

Amount 를 private 로 만들기

상념 2 : 실수 연산일텐데 , 반올림 처리는 ? 대처 2 : TODO 리스트에 다음을 추가한다

Money 반올림 ?

상념에 방해받지 말자 . TODO List 가 기억 !

Page 22: Software development #2: Test-Driven Development

Test 결과에 대한 적절한 대처

한번의 코딩으로 초록 막대를 보지 못함을 슬퍼할 이유는 전혀 없다 결국은 초록 막대를 볼 것임을 우리는 안다

가장 단순한 해결책을 찾는다 five 객체의 amount 변수의 값이 10 이

아니어서 통과하지 못한 것이라고 했었다

결론 : 객체의 amount 변수의 값이 10이어야 !

Page 23: Software development #2: Test-Driven Development

가장 간단한 코드 수정

Public class Dollar {

int amount = 10;

public Dollar(int amount) {

}

void times(int multiplier) {

}

}

Page 24: Software development #2: Test-Driven Development

Test 실행

결과 모든 테스트가 성공한다

의의 오직 테스트를 통과시키기 위한 목적의 코딩 . 이런 코드는 사실 죄악이다 .

그리고 그런 죄악을 저지르자 . 왜 ? 프로그램 개발 = 테스트 코드를 만들고

그 테스트를 통과시켜 초록 막대를 보는 거니까 !

그리고 죄악은 수습하면 그만이다 .

Page 25: Software development #2: Test-Driven Development

죄악의 수습

죄악을 저지르는 이유 테스트 케이스에 대해 빨간 막대를 유지하면

심리적인 불안감이 조성된다 기분이 나쁘고 언짢다

따라서 최대한 빨리 초록 막대를 보는 게 낫다

죄악을 수습하는 방법 처음부터 죄를 저지르지 않는다 Refactoring 을 실시한다

Page 26: Software development #2: Test-Driven Development

Cf) Refactoring

정의 The process of changing a program's source

code without modifying its external functional

behavior in order to improve some of the

nonfunctional attributes of the software.

간단히 말하면 함수 / 파라메터 이름만 살짝 바꾸는 것 함수의 내부 구조만 바꾸는 것

Page 27: Software development #2: Test-Driven Development

어떤 때 Refactoring 을 하는가 확실한 성능의 개선이 있을 때

예 ) 정렬을 담당하는 함수가 하나 있는데 알고리즘을 Bubble Sort 로 했는데 나중에 정렬하는 핵심 코드만 Quick Sort 로 바꾸기

좀 더 가독성이 좋은 소스 코드로 바꿀 때 예 ) 변수 이름이 a, b, c, d, 이런 식인데

변수 이름을 gender, name, age, grade 하는 식으로

좀더 그 기능과 연관되는 이름으로 바꾸기

Page 28: Software development #2: Test-Driven Development

TDD With Refactoring

초록 막대 주기에서 Refactoring 을 하는 이유 Refactoring 이후에도 초록 막대를 본다는 것은

진짜로 External Behavior 는 바뀌지 않았음이보장된다는 것을 의미

Refactoring 하고 나서 빨간 막대가 나타난다는 것은뭔가 Refactoring 하다가 실수 했다는 뜻이니

실수를 바로잡을 기회가 생김

TDD 방법론의 특성이 안전한 Refactoring 을 보장하는 셈이다

Page 29: Software development #2: Test-Driven Development

Typical TDD Refactoring

죄악 수습용으로서의 Refactoring 죄악들의 공통된 특징

Test Code 에 쓰인 상수를 프로그램 Code 에도 그대로 쓴다

어떤 형태로든 중복이 발생한다 코드의 중복은 나쁜 것 코드의 중복을 제거한다 !

성능 개선을 위한 Refactoring 성능 개선을 알아볼 수 있는 Test 도 추가하면 좋다

Page 30: Software development #2: Test-Driven Development

중복되는 코드 찾기 , #1

테스트 코드의 상수와 코드 내부의 상수 밑줄 친 부분을 잘 관찰하자

Dollar five = new Dollar(5);

five.times(2);

int amount = 10;

Page 31: Software development #2: Test-Driven Development

5 * 2 = 10

테스트 코드의 assertEqual 의 10 은 사실 New Dollar 의 5 와 five.times 의 2 의 곱이다 !

Dollar five = new Dollar(5);

five.times(2);

int amount = 10;

Page 32: Software development #2: Test-Driven Development

중복이 더 잘 드러나도록

amount 에 대응된 10 을 5 * 2 로 고쳤다 이제 하나씩 하나씩 각개 격파해보자

Dollar five = new Dollar(5);

five.times(2);

int amount = 5 * 2;

Page 33: Software development #2: Test-Driven Development

중복되는 5 가 등장하는 변수를

Dollar five = new Dollar(5);

……

int amount = 5 * 2;public Dollar(int amount) {

상수와 같은 값을 지니는 변수를 찾자 객체 생성자의 파라메터에 주목 !

Page 34: Software development #2: Test-Driven Development

변수를 이용하여 상수를 대체해

Dollar five = new Dollar(5);

……

int amount; // = 5 * 2;

public Dollar(int amount) {

this.amount = amount * 2;

}

생성자의 amount 파라메터로 넘어오니까 굳이 Member variable 초기화에서 안해도 된다 !

Page 35: Software development #2: Test-Driven Development

Test 실행

Test 실행 매끄럽게 성공한다 .

죄악의 수습 동일한 상수가 이곳 저곳에 있던 것을 최소한 상수는 중복되지 않도록 수정해 나가면 결국은 아름다운 코드가 나올 수 있게 된다 !

그래도 기왕이면 죄악을 저지르지 말자 .

Page 36: Software development #2: Test-Driven Development

상수 2 를 없애보자

five.times(2);

상수와 같은 값을 갖는 변수 찾기가 관건 !

public Dollar(int amount) {

this.amount = amount * 2;

}

void times(int multiplier) {

}

Page 37: Software development #2: Test-Driven Development

파라메터 multiplier 발견

five.times(2);

……

public Dollar(int amount) {

this.amount = amount;// * 2;

}

void times(int multiplier) {

this.amount *= multiplier;

}

용서없다 . 죄악은 척살이다 .

Page 38: Software development #2: Test-Driven Development

Test 실행

결과 결국 성공한다 .

더 리펙토링할 곳이 보이지 않는다 죄악은 전부 수습되었다 이 정도면 충분히 깔끔한 코드인 듯 싶다 테스트도 전부 통과한다

이번 TDD Rhythm 주기는 여기까지로 하자 !

Page 39: Software development #2: Test-Driven Development

한 주기가 끝난 아름다운 소스

Public class Dollar {

int amount;

public Dollar(int amount) {

this.amount = amount;

}

void times(int multiplier) {

this.amount *= multiplier;

}

}

Page 40: Software development #2: Test-Driven Development

TDD 는 매우 Agile 하다

Comprehensive Documentation 보다Working Software Test 를 통과하는 Software == Working

Software 무슨 수를 써서라도 Test 부터 통과시키자

죄악을 저질러도 상관 없다 용서받기만 하면 장땡이다

함수의 구조에 대한 복잡한 설계 과정 없이Test Code 에 맞추는 것만으로도 Working Software 를 얻을 수 있다

Page 41: Software development #2: Test-Driven Development

TDD 는 매우 Agile 하다

Follow Plan 보다 Respond to Change 각각의 할 일들은 한번에 하나씩만 처리한다

어느 것을 먼저 처리해도 문제될 것은 없다 Test 만 작성할 수 있으면 된다

고객 요구 조건의 변화는 결국 새로운 Test 의 추가에 지나지 않는다 그리고 그건 TDD Rhythm 한번 타면 해결된다

Cf) TDD 에서는 기존의 Test Code 를 제거하는 것도 물론 일어날 수 있는 일로 보고 있다 .

엄청나게 기민하다 !

Page 42: Software development #2: Test-Driven Development

eXtreme Programming 과의 조화 경제성

“ 설계” 와 “ 테스트” 가 하나로 합쳐짐 테스트 그 자체가 함수의 Interface 를 정의함 !

점진적 설계 Test Code 는 한번에 하나씩 만드니 점진적

설계 !

자동화된 테스트 TDD 는 언제나 자동화된 테스트를 만든다 !

Page 43: Software development #2: Test-Driven Development

But TDD is too eXtreme!

모든 프로그래밍을 TDD 로 할 필요가 있나 ? 반드시 Test 를 먼저 짜야만 프로젝트가

진행될 수 있는 것만은 아니다 .

TDD 주기는 지나치게 엄격하다 테스트 실패를 굳이 매번 확인할 필요는 없다 언제나 “ 죄악” 부터 저지르고 리펙토링해 ? 하나의 Test Code 만 통과시킨다고 해서

제대로 작동하는 프로그램을 못 만들 때도 있다

Page 44: Software development #2: Test-Driven Development

Just one more TDD Rhythm.

Page 45: Software development #2: Test-Driven Development

Recalling TO-DO List

아까 한 개의 할일이 처리되었지만 두 개의 할 일이 늘어났다

TO-DO List $5 + 10YEN = $6 ( 환율이 1:10 일 때 ) $5 = $5 ( 서로 다른 계좌 ) 어쨌든 이걸 골랐다

amount 를 private 로 이건 기존 Test Code 수정으로 충분할듯

반올림 ?

Page 46: Software development #2: Test-Driven Development

Test Code 추가

두 개의 Dollar 객체를 만들어서 그 둘에게 equals 메소드를 적용하면

true 값이 나오는지를 확인하자 .

public void testEquality() {assertTrue(

new Dollar(5).equals(new Dollar(5));

}

Page 47: Software development #2: Test-Driven Development

Test 실행

Test 실행 당연히 실패한다 .

왜 굳이 실패해야 할까 ? 어차피 새로운 Test 를 추가하면 실패하는 건

너무 당연한 일이 아닐까 ? No! 이미 “ 잘못” 구현되어 있어야 하는 메소드가

있는데 그 메소드가 “ 잘못” 구현되어있다는 예측을 벗어난다는 것을 검증하게 되는 경우도 있음

그리고 Test 실패를 관찰하는 건 0.1 초면 충분 ! 그닥 시간낭비도 아니니까 걍 해주자 . ㅋㅋ

Page 48: Software development #2: Test-Driven Development

마음놓고 죄악 저지르기

최대한 단순하게 equals 메소드를 작성하자

Public class Dollar {

public boolean equals(Object object) {

return true;

}

}

Page 49: Software development #2: Test-Driven Development

Test 실행과 그 후 …

결과 당연히 … 잘 통과한다 .

Refactoring 할 거리를 찾아야 한다 우리에게는 죄악이 만든 true 라는 상수가

있다 분명히 이 상수는 다른 상수와 중복이다 아까 10 = 5 * 2 였던 것처럼 , 이 true 도 뭔가 아주 당연한 연산에서 왔을 것

근데 … 도저히 못찾겠다면 ??

Page 50: Software development #2: Test-Driven Development

난관에 봉착했다 .

원인 분석 Refactoring 스킬이 부족하다면 엄밀히 따지면 코드 중복이지만 대충 봐서는 파악하기 힘든 경우에 도저히 대처를 할 수가 없다

대응 방법 Refactoring 스킬을 조홀라 키운다 Test Code 를 좀 더 잘 짠다

Page 51: Software development #2: Test-Driven Development

대응 방법 1 을 따른다면

일단 상수 true 를 다른 상수로 표현해 보자 . 논리값 true 가 나올 수 있는 가장 대표적인 경우

라면 역시 “ ==“ 연산자 사용이다 . Test Code 에는 동일한 상수 5 가 2 회 나온다 . 이 상수들은 서로 다른 파라메터로 전달된다

따라서 true 를 일단 5 == 5 로 고쳐보자 다시 각각을 this.amount 와 (Dollar)object.amount 로 고치는 게 가능하다

Page 52: Software development #2: Test-Driven Development

대응 방법 1 의 한계점

너무 뛰어난 추론능력이 필요하다 추론은 곧 경험에서 우러나온다 경험이 부족한 사람은 대응 방법 1로 할 수

없다

경험이 쌓이기에는 시간이 걸린다 TDD 초심자가 처음부터 저런 좋은 길을 걷기는 매우 힘들다

결국 TDD 를 기피하게 될지도 …

Page 53: Software development #2: Test-Driven Development

아니 , 대응 방법 2 로 가보자 ! TDD 원칙을 완전히 따르려면

최초부터 테스트 코드를 작성할 적에2가지 경우의 수를 고려해 본다

TDD 스럽게 하기만 하면 된다면 테스트 코드가 좀 부족했음을 인정하고

한꺼번에 통과시킬 테스트 코드를 … 추가하여전체 테스트를 통과시키기 위해 노력해보자물론 이때는 지금까지의 죄악은 싸그리 초기화해

쓸데 없는 죄악때문에 헷갈릴 수 있으니까

Page 54: Software development #2: Test-Driven Development

Test Code 추가부터 다시 간다

처음부터 2 가지 경우를 고려해 보자 !public void testEquality() {

assertTrue(new Dollar(5).equals(

new Dollar(5));assertFalse(

new Dollar(5).equals(new Dollar(6));

}

Page 55: Software development #2: Test-Driven Development

Test 실행

결과는 ? 당연히 실패한다 .

가장 단순한 해결책은 ? 자세히 보니 true 인가 false 인가를 가르는

차이점이 하나 눈에 보인다 메소드 eqlaus 의 파라메터로 들어오는

객체의 amount 값이 5 인가 6 인가에 달려 있다 !!

Page 56: Software development #2: Test-Driven Development

죄악을 저지르자

괜찮아 이 모든 건 초록막대를 보고싶어서…

Public class Dollar {

}

public boolean equals(Object object) {

return (Dollar)object.amount == 5;

}

}

Page 57: Software development #2: Test-Driven Development

Test 실행

결과 잘 통과한다 .

같은 죄악이지만 급이 다르다 Test Code 가 쓸 데 없이 둘이나 있는 듯 싶다 나중에 Test Code 자체에 대한 Refactoring

도하는 날이 올 것이다

하지만 결과적으로 좀더 나은 코드를 가져왔다

이런 Test Code 를 “삼각측량” 이라 한다

Page 58: Software development #2: Test-Driven Development

Refactoring 을 위해 !

상수의 중복이 훨씬 직관적으로 보인다…

new Dollar(5).equals(

new Dollar(5).equals(

……

public Dollar(int amount) {

this.amount = amount;

public boolean equals(Object object) {

return (Dollar)object.amount == 5;

Page 59: Software development #2: Test-Driven Development

중복이 되는 5 를 제거한다

결국 이건 this.amount 다 !…

new Dollar(5).equals(

new Dollar(5).equals(

……

public Dollar(int amount) {

this.amount = amount;

public boolean equals(Object object) {

return (Dollar)object.amount == this.amount; // 5;

Page 60: Software development #2: Test-Driven Development

테스트 실행

결과 아주 잘 통과한다 .

또 하나의 주기가 끝나다 ! 이런 식으로 계속 한 기능씩 한 기능씩 점진적

진행을 해 나가도록 하자 . 아무리 거창해 보이는 프로젝트라도 TDD

주기 단위로 쪼개버리면 별거 아니다 .

Page 61: Software development #2: Test-Driven Development

Google loves TDD

Google Testing Blog http://googletesting.blogspot.com/

Testing on the Toilet Introducing numerous Testing

Techniques http://googletesting.blogspot.com/2007/

01/introducing-testing-on-toilet.html

Page 62: Software development #2: Test-Driven Development

SUMMARY

Test-Driven Development (TDD) 이란 ,코드 작성에 앞서 반드시 작성할 코드를 검증할 테스트 코드부터 작성한 뒤에 코드를 작성하는 것을 원칙으로 하는 프로그램 개발 방법론이다 .

테스트 코드 추가 , 실패 , 간단한 구현 , 테스트 통과 , 리펙토링의 순서로 개발을 진행한다 .

TDD 철학대로만 강박관념을 갖고 코딩을 하는 것이 좋은 것만은 아니지만 , 적어도 Testing 의 강력한 힘에 따라 XP 와 잘 섞어쓸 수 있다 .

Page 63: Software development #2: Test-Driven Development

References

Kent Beck, 테스트 주도 개발 김창준 , 강규영 역

http://www.javajigi.net/pages/viewpage.action?pageId=278