설모의 기록

[우아한테크캠프] 3일차 본문

일상/우아한테크캠프

[우아한테크캠프] 3일차

HA_Kwon 2018. 7. 4. 20:15


TDD (Test Driven Development) ?


개발을 생각의 흐름대로 진행하다보면, 중간의 결과값을 알아보고 싶지만 그 값을 알기 위해서 해야 할 작업들이 너무 많아 포기할 때가 종종 있었을 것입니다. DB 조회 코드만 생각해도 데이터베이스에 해당 데이터가 있는지만 조회하려 해도 데이터베이스 환경을 세팅하는 코드를 실행하고, connection 을 연결하는 코드를 실행해야 비로소 데이터를 조회할 수 있습니다. 

이럴 때 유용한 것이 단위 테스트입니다. 그리고 단위 테스트를 언제 작성하고 수행해야 하는지를 나타내는 방식이 TDD입니다. TDD 방식을 이용하지 않으면 일반적으로 테스트 코드를 작성하기 어렵도록 코드를 구현합니다. 그렇다보니 테스트 코드를 작성하기 어려워 '하지말자!' 또는 '다음 로직만 구현하고 테스트 코드 작성하자!' 하고 넘어가게 되죠. 저도 오늘 TDD방식으로 코드를 구현하는 것에 익숙해지는 것이 너무 어려웠습니다. 프로그램을 구현하다보면 '아 이거 5분이면 짤 수 있는데, 이것만 짜고 테스트 코드 구현하자' 하는 마음으로 구현하게 되고, 결국 테스트 코드는 등진 채  프로그램을 모두 구현하게 되어 반성하는 계기가 되었던..

그런데 처음부터 프로그램을 TDD로 구현해보니 어떤 것을 구현해야 하는지를 알고, 어떤 경우에 프로그램이 에러를 발생하는지를 확실히 알게 되어 실수를 줄이는 계기가 되었습니다. 


TDD = TFD (Test First Development) + refactoring

TDD는 위에 작성한 대로 TFD와 리팩토링을 합친 작업입니다. TDD를 올바르게 수행하기 위해서는 (1) 요구사항을 분석, (2) 좋은 설계 기술 이 필요합니다. 

TDD 방식으로 코드를 구현하는 이유는 아래와 같습니다.

  • 디버깅 시간을 줄여줍니다. 디버깅 툴을 이용해 코드를 디버그 하다 보면 하나하나의 실행 흐름을 알아야 하기 때문에 오래 걸릴 수도 있습니다. 이럴 때 TDD 방식을 이용하면 간단하게 테스트 해볼 수 있습니다.
  • 동작하는 문서 역할을 합니다. 예를 들어 제가 api를 작성했다면 api를 어떻게 사용해야 하는지를 테스트 코드를 이용해 알려줄 수 있기 때문입니다.
  • 변화에 대한 두려움을 줄일 수 있습니다. 리팩토링 과정을 통해 클린 코드 (clean code) 로 수정하면 되기 때문입니다.




TDD 사이클


TDD 방식의 사이클은 위의 이미지와 같습니다. 먼저 테스트 코드를 작성한 후 컴파일 에러만 수정해 테스트를 실행합니다. 실행 결과가 fail이면 이제 프로덕션 코드를 작성합니다. 이 때는 clean code를 작성하기 위해 노력하지 않아도 되며 실행이 success 만 되도록 구현하면 됩니다. 이렇게 success 단계까지 왔다면 refactoring 과정을 통해 clean code로 개선해나가면 됩니다. 지금까지 TDD 방식으로 코드를 구현해오지 않은 분들은 다소 어색하실 수 있습니다. 그러나 실제로 구현해보면 TDD 만의 장점을 느끼실 수 있습니다.




TDD 원칙


TDD 원칙은 아래와 같습니다.

  • 실패하는 단위 테스트를 작성할 때까지 프로덕션 코드를 작성하지 않습니다.
  • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
    -> 빨리 구현하고 심리적으로 여유를 가지고 리펙토링을 합니다. 구현과 설계를 함께 하려다 두 마리 토끼를 모두 놓치지 말고 구현을 먼저 한 후 리펙토링 과정에서 제대로 된 설계를 합니다.
  • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성합니다.

위의 원칙을 항상 생각하며 단위 테스트를 구현한 후 실제 코드를 작성해 나가야 합니다. 이를 위해서는 아래의 흐름대로 구현하도록 노력해야 합니다.

  1. 먼저 요구사항을 보며 TODO LIST를 작성합니다. (예 : 콤마로 자동차 이름을 나눠야지, 자동차 중 우승 자동차 구해야지, ...)
  2. TODO LIST를 바탕으로 input을 넣으면 output이 나올 정도로만 테스트 코드를 작성합니다.
  3. 그 테스트 코드에서 발생하는 컴파일 에러를 해결할 수 있을 정도로만 프로덕션 코드를 작성합니다. (예 : 메소드 body만 작성하기, ...)
  4. 실행하여 결과가 fail이 뜬다면 success가 되도록 코드를 구현합니다. 이 때, 설계를 제대로 하려고 노력하지 않아도 됩니다. 코드가 정상적으로 실행 되도록만 코드를 작성하시면 됩니다.
  5. 코드 실행이 정상적으로 실행됐다면 이제는 refactoring 과정을 통해 작성한 프로덕션 코드를 clean code로 수정해 나갑니다. 이 과정에서 프로덕션 코드에서의 메소드 안에서는 동일한 추상화 레벨을 가진 코드가 존재해야 합니다. 또한 프로덕션 코드 뿐만 아니라 테스트 코드도 refactoring 과정이 필요합니다.




오늘의 팁


우아한테크캠프 3일차 강의에서 배운 자바 프로그래밍의 팁입니다.

  • 객체를 비교할 때는 객체의 변수를 꺼내 비교하려 하지 말고 객체의 클래스에 equals(), hasCode() 메소드를 오버라이드한 후, 객체 자체를 비교하는 것이 좋습니다. 이러한 과정이 객체지향적 프로그래밍입니다. 상태를 뽑아서 비교하다보면 결국 절차지향적 프로그래밍이 됩니다.
  • List를 생성해 객체를 채워나가는 과정을 for문을 이용해 긴 코드로 구현하는 대신에,
    -> List<String> names = Arrays.asList("h", "y", "e", "o", "n", "a");
    를 이용해 한 줄로 쉽게 구현할 수 있습니다.
  • 생성자 오버로딩을 통해 여러 생성자가 있는 경우에 중복 코드가 발생할 수 있습니다. 예를 들어,
    Car(int position) {
        this.position = position;
    }

    Car(int position, String name) {
        this.position = position;
        this.name = name;
    }

    이러한 코드는 아래와 같이 수정할 수 있습니다.
    Car(int position) { this(position, "hyeona"); }

    Car(int position, String name) {
        this.position = position;
        this.name = name;
    }

  • List에서 특정 조건을 만족하는 객체만 다시 List로 만드는 방법은 stream을 이용해 아래와 같이 간단하게 구현할 수 있습니다.
    // car도 List 입니다.
    List<Car> winners = car.stream()
                        .filter(car -> car.isMaxPosition(maxPosition))
                        .collect(Collectors.toList());

  • 특정 객체를 생성하는 클래스는 일반적으로 Factory, Generator 라는 이름을 사용합니다.


'일상 > 우아한테크캠프' 카테고리의 다른 글

[우아한테크캠프] 7일차  (0) 2018.07.11
[우아한테크캠프] 6일차  (0) 2018.07.09
[우아한테크캠프] 5일차  (0) 2018.07.07
[우아한테크캠프] 4일차  (0) 2018.07.06
[우아한테크캠프] 2일차  (0) 2018.07.03
Comments