[테스트 주도 개발] 12장_드디어 더하기

전체 더하기 기능에 대한 스토리를 어떻게 적어야할지 모르겠다. 간단한 예, “5 달러 + 5달러 = 10 달러” 에서 시작하자.

1
2
3
4
5
@Test
void testSimpleAddition() {
Money sum = Money.dollar(5).plus(Money.dollar(5));
assertEquals(Money.dollar(10), sum);
}

그냥 Money.dollar(10) 을 반환하는 식으로 가짜 구현을 할 수 있지만, 어떻게 구현할지 명확하므로 다음과 같이 하겠다.

1
2
3
4
// Money
Money plus(Money addend){
return new Money(amount + addend.amount, currency);
}

다중 통화 사용에 대한 내용을 시스템의 나머지 코드에 숨기고 싶다. ( 2달러 + 3CHF ) * 5 를 보자. Money 가 수식의 가장 작은 단위가 된다. 연산의 결과로 Expression 들이 생기는데, 그 중 하나가 sum 이다. 연산이 완료되면 환율을 이용해서 결과 expression 을 단일 통화로 축약할 수 있다. 이런식으로 테스트할 수 있다.

1
2
3
4
5
@Test
void testSimpleAddition() {
....
assertEquals(Money.dollar(10), reduced);
}

reduced 란 이름의 expression 은 expression 에 환율을 적용해서 얻어진다. 실세계에서 환율이 적용되는 곳은 어디인가 ? 은행이다.

1
2
3
4
5
6
@Test
void testSimpleAddition() {
...
Money reduced = back.reduce(sum, "USD");
assertEquals(Money.dollar(10), reduced);
}

여기서, 단순히 “…reduce = sum.reduce(“USD”, back)” 라고 할수 있었다. 왜 Back 가 reduce() 를 수행할 책임을 맡았을 까 ?

  1. Expression 은 하려고 하는 일의 핵심이다. 핵심이 되는 객체가 다른 부분에 대해서 될 수 있는 한 모르도록 하자. 그러면, 핵심 객체가 가능한 오랫 동안 유연할 수 있다. 그리고, 테스트하기도 쉽고 재활용하거나 이해하기에 쉽다.
  2. Expression 과 관련이 있는 오퍼레이션이 많은 수 있다. 모든 오펴레이션을 Expression 에만 추가하면 Expression 는 무한히 커진다.
1
2
3
4
5
6
7
@Test
void testSimpleAddition() {
...
Bank bank = new Bank();
Money reduced = bank.reduce(sum, "USD");
assertEquals(Money.dollar(10), reduced);
}

두 Money 의 합은 Expression 이어야한다.

1
2
3
4
5
6
7
8
@Test
void testSimpleAddition() {
...
Expression sum = five.plus(five);
Bank bank = new Bank();
Money reduced = bank.reduce(sum, "USD");
assertEquals(Money.dollar(10), reduced);
}

5 달러를 만드는 것은 쉽다.

1
2
3
4
5
6
7
8
@Test
void testSimpleAddition() {
Money five = Money.dollar(5)
Expression sum = five.plus(five);
Bank bank = new Bank();
Money reduced = bank.reduce(sum, "USD");
assertEquals(Money.dollar(10), reduced);
}

이걸 컴파일하려면 어떻게 해야하나 ? Expression 인터페이스가 필요하다. 클래스도 되지만, 더 가볍다.

1
2
interface Expression {
}

Money.plus 는 Expression 을 반환해야한다.

1
2
3
Expression plus(Money addend){
return new Money(amount + addend.amount, currency);
}

이건, Money 가 Expressoin 을 구현해야한다는 뜻이다. Expressoin 에 아직 아무 연산이 없으니 쉽다.

1
class Money implements Expression {

이제 빈 Back 클래스가 필요하다.

1
2
class Bank {
}

그리고 reduce() Stub 이 필요하다.

1
2
3
4
5
6
class Bank {

Money reduce(Expression source, String to) {
return null;
}
}

이제 컴파일 되고, 바로 실패한다. 간단히 가짜 구현을 하자.

1
2
3
4
5
6
class Bank {

Money reduce(Expression source, String to) {
return Money.dollar(10);
}
}

다시 초록막대. 리팩토링하자.


테스트 주도 개발 <켄트 벡>

Comments