dev.log2009. 10. 27. 04:15
TDD는 코딩 전에 테스트를 정의하는 방법론이다. TDD가 말하는 바는, 작성하는 코드가 어떻게 동작하여야 하는지를 정의하고, 이 정의에 부합하도록 동작하는지, 그리고 이 정의에 부합하지 않는 쪽으로 동작하지 않는지를 검증하는 코드를 먼저 짜야 한다는 것이다. 내가 지금까지 코딩해왔던 방식이랑 비교하자면, 난 일단 특정 모듈의 행동양식을 정의하고, 사용처에서 사용하고자 하는 방식을 적어놓고 컴파일해본다. 컴파일 에러가 모두 사라지고 구현하면 동작하는 코드가 나오는 방식.
의식의 흐름 기법으로 정리해 보면.
  1. "파일에서 뭘 하나 읽어와야겠군"
    int XXX::open_file( const string& filename )
    {
    }
  2. "그럼 스트림을 추상화해야겠군"
    int XXX::open_file( const string& filename )
    {
        stream file( filename );
        file.read( this->buffer, this->size );
    }
  3. "컴파일 에러로군"
    class stream
    {
    public:
        stream( const string& name );
        int read( void* buffer, size_t size );
    };

    int XXX::open_file( const string& name )
    {
        stream file( name );
        return file.read( this->buffer, this->size );
    }
  4. "구현을 해야겠지?"
    class stream
    {
    public:
        stream( const string& name );
        int read( void* buffer, size_t size );
    };

    int XXX::open_file( const string& name )
    {
        stream file( name );
        return file.read( this->buffer, this->size );
    }

    stream::stream( const string& name )
    {
        // ...................
    }
    int stream::read( void* buffer, size_t size )
    {
        // ...................
    }
  5. "파일이 제대로 열리나?"
    class stream
    {
    public:
        stream( const string& name );
        int read( void* buffer, size_t size );
    };

    int XXX::open_file( const string& name )
    {
        stream file( name );
        return file.read( this->buffer, this->size );
    }

    stream::stream( const string& name )
    {
        // ...................
    }
    int stream::read( void* buffer, size_t size )
    {
        // ...................
    }

    int main()
    {
        // ...................
        XXX x;
        int result = x.open_file( ",,,,,,,,,,,,,,,," );
        assert( result != ERROR );
        assert( memcmp( x.buffer, dummy ) == 0 );
    }
  6. "버그 잡자"
내가 코딩하는 방식과 TDD에서 제시하는 방식의 차이는, 바라는 동작을 정의하는 부분이 워킹 코드이냐 테스트용 코드이냐 하는 점이다. 지금 내 방식의 단점은, 코드가 바뀌고 나면 동작의 일관성이 깨져도 그걸 체크할 방법이 바뀐 코드와 함께 유실돼 버린다는 것. TDD의 유용성이 느껴지는 부분이다.

TDD의 방법론은 실천 지침이 명확하다는 점에서 유용한 듯 하다. "코드보다 테스트코드 먼저". 이 얼마나 간단 명료한 지침인가. 내 생각으로는, 이 간단한 지침에 숨겨진 효용은 대충 이런 것 같다. 테스트를 작성하기 위해서는 내가 쓰고자 하는 코드가 어떤 식으로 동작해야 하는지를 정의해야 한다. 동작을 정의하기 위해서는 설계를 머리 속에 담고 있어야 하고, 이는 결국 코딩하기 전에 생각하라-는 오래된 금언을 실천하기 위한 매우 유용한 방법론인 것이다.
생각해 보면, 코딩하기 전에 생각하는 것이 습관화된 사람에게 TDD는 별달리 임팩트를 주진 않을 것 같다. TDD의 사용자에게 작용하는 궁극적이고 장기적인 영향은 코딩하기 전에 생각하는 습관을 들이게 하는 거라는 점에서 그렇다. (TDD의 다른 장점은 프로젝트에 작용하는 장점이지, 사람에게 작용하는 장점이 아니다) 하지만 그럼에도 장점은 있는데, 일단 남들에게 가르치기 쉽고, 또한 각 단계가 매우 짧고 보상이 정확하기 때문에 마치 게임을 하는 것처럼 코딩을 할 수 있다는 거다. "만렙까지 알아서 레벨 올리세요"와 "남쪽골짜기에서 토끼를 잡으면 레벨이 하나 올라요"의 차이랄까. 나에게 TDD란, 프로그래밍이란 게임의 규칙이란 느낌. 한 단계씩 레벨 올려서 만렙이 되면 프로그램이 완성되는 게임.

Posted by uhm