Search Results for '테스트'

3 POSTS

  1. 2008.03.28 디버거 없이 개발하기 2
  2. 2006.12.19 컴공과 프로젝트와 테스트성(testability) 2
  3. 2006.08.30 테스트 주도 개발

디버거 없이 개발하기

Posted 2008. 3. 28. 20:09

전 개발할 때 디버거를 자주 사용하지 않는 편입니다. C/C++, 자바, 파이썬, 하스켈 등 개발 언어를 가리지 않고 디버거는 거의 사용하지 않습니다. 물론 디버거를 안 사용하는 게 무슨 개발 철학 같은 건 아닙니다. 직관적으로 디버거를 사용하는 편이 좋겠다는 생각이 들 때도 있고 프로그램이 C 코드 안에서 죽을 때는 디버거를 실행시켜서 메모리와 변수 값을 보기도 합니다.

하지만 디버거로 절대 잡기 힘든 멀티쓰레드 버그가 난무하고 메모리 보호도 없는 임베디드 시스템 개발로 개발을 시작하다보니 버그가 생겨도 디버거를 써야지라는 생각을 잘 안 하게 된 것 같습니다. 대신 저는 디버깅에 크게 2가지 방법을 사용합니다. (다른 개발자도 마찬가지겠지만요)

1) 콘솔 출력

언어마다 다르지만 결국 중요한 지점 몇 군데가 변수 값을 찍어보는 걸로 디버깅이 시작됩니다. printf, System.out.println, print가 디버깅 도구인 셈이죠. 간단한 버그들은 보통 원인이 짐작이 되기 때문에 중요 변수를 콘솔로 몇 번 출력해 보면 문제가 파악됩니다.


2) 코드 검토

멀티쓰레드 버그에 대해서는 가장 강력한 디버깅 방법이 머리 속으로 시뮬레이션하는 것입니다. 증상을 놓고 왜 이런 문제가 생겼을지 의심가는 여러 쓰레드를 놓고 생각해 보는 것이죠. 하루종일 책상에 앉아서 왜 이런 현상이 생길지 생각만 하다가 집에 간 날도 있습니다.


버그를 찾아내면 기쁘긴 하지만 디버깅 자체는 괴롭습니다. 처음부터 버그를 안 만드는 게 최선이겠죠.  하지만 나름대로 열심히 짠다고 해도 버그 없는 프로그램을 만들기란 너무 힘듭니다. 코드를 작성했는데 한 번에 컴파일되고 돌아가면 스스로 의심합니다. "그럴리가 없는데." 어릴 때는 그래도 머리가 잘 돌아가서 가끔 실행은 제대로 안 되더라도 컴파일 에러 없는 코드 정도는 만들어내곤 했는데 요즘은 그나마도 힘들어 그냥 포기하고 무슨 마약처럼 컴파일러에 의존(주기적으로 컴파일을 해보지 않으면 불안함)해 살고 있습니다.

버그는 사람이 만들지만 버그를 유도하는 것은 개발 환경입니다. 특히 프로그래밍 언어는 개발자가 얼마나 많은 버그를 만드는지를 결정하는 중요한 요소입니다. 함수 언어를 사용하면서 느낀 점 중에 하나는 적당히 컴파일되게만 짜면 다른 언어에 비해 버그가 현저히 적다는 사실입니다. 물론 강력한 정적 타입 시스템에 도움이 큰 셈이죠. 여기에 덧붙여 버그를 줄이는 프로그래밍 언어의 특징으로는 변조불가능(Immutability), 순수(Purity), 참조 투명성(Referential Transparency) 등이 있습니다. 세 가지 단어는 서로 다 관련이 있습니다.

하스켈을 비롯한 함수 언어 개발자들이 다른 개발자들과 차이를 보이는 점 중에 하나가 디버거를 거의 사용하지 않는다는 사실입니다. 물론 GHCi에 보면 디버거가 없는 건 아닙니다. 앞서 언급한 언어적 특성 때문에 하스켈 디버깅은 디버거를 통해 변수에 잘못된 값이 들어가 있는지 확인하는 일이 필요가 없습니다. (사실 변수라고 부를만한 것도 별로 없습니다.) 그저 함수 명세에 맞춰서 코드가 제대로 작성되었는지 테스트 값 몇 개만 넣어보면 됩니다.

특히 하스켈의 중요 특징의 하나인 참조 투명성은 테스트 혹은 디버깅에서 강력한 힘을 발휘합니다. 참조 투명성이란 하스켈의 함수가 수학적인 함수와 동일하게 같은 입력(인자)에 대해서는 언제나 같은 값을 리턴함을 의미합니다. 하스켈의 순수 함수는 전역 변수를 참조하거나 IO에 영향을 받지 않기 때문에 테스트나 디버깅을 위해 가짜 오브젝트(Mock Object) 등을 만들어내는 수고를 할 필요가 없습니다. 그저 함수의 명세(specification)만 테스트하면 됩니다. 이런 특성 때문에 하스켈의 테스트프레임워크 중 하나인 QuickCheck은 명세 기반 테스트라는 용어를 사용하고 있습니다.

나는 연장질을 잘 못한다고 생각하기 보다는 내 연장이 나쁜게 아닐까라는 생각의 전환이 필요합니다.

컴퓨터공학과 학생들은 어떤 수업을 듣던지 적으면 1-2개에서 많은 5-6개의 프로그래밍 프로젝트를 하게 됩니다. 이런 프로젝트를 하면서 아쉬웠던 점은 프로그래밍 프로젝트의 명세서가 명료하지 못하고 나중에 어떻게 평가할지(테스트할지) 전혀 고려하지 않고 있다는 것입니다. 다음은 포항공대 컴퓨터공학과 네트워크 수업에서 네 번째 프로젝트로 나온 라우팅 프로토콜(routing protocol) 구현 프로젝트입니다.



프로젝트의 목표는 네트워크 수업 시간에 배우는 대표적 라우팅 알고리즘 2가지(Link State Algorithm, Distance Vector Algorithm)를 구현하는 것입니다. 프로젝트를 읽어보면 아시겠지만 이걸 학생들이 각자 마음대로 구현했을 때 조교 입장에서 학생들의 프로그램을 조직적으로 테스트할 방법이 거의 없습니다. 직접 찾아가서 데모 형태로 보여줘야 하고, 데모를 해도 제3자의 입장에서 해당 프로토콜이 정말 제대로 동작하는지 알기가 어렵죠.

반대로 교환학생으로 메릴랜드에서 수업을 들을 때는 달랐습니다. 그들은 프로젝트를 내주기 전에 해당 프로젝트에 대한 테스트 케이스를 작성하고, 어떤 부분들을 평가할 것인지는 명료하고 정확하게 제시합니다. 학생들이 프로젝트를 제출하면 미리 작성된 테스트 케이스를 돌려보고 곧바로 점수를 매겨줍니다. 어떤 과목은 이 과정까지 자동화해서 웹으로 프로젝트를 작성해서 제출하면, 곧바로 어떤 테스트 케이스를 통과했고 실패했는지까지 일목요연하게 보여주더군요.

조금만 신경쓰면 아주 멋진 프로젝트를 내줄 수도 있을텐데 조금 아쉽네요 :(

테스트 주도 개발

Posted 2006. 8. 30. 19:11
The case for static types라는 IBM developers@work의 기사를 읽다가 괜찮은 아이디어를 얻었다.

Extreme Programming에서는 코드 작성 이전에 테스트 케이스를 만드는 게 좋다고 권고하는데, 자바처럼 StaticType Check하는 언어의 경우 테스트를 먼저 만들어도 컴파일해 볼 수 없다는 문제가 있다. 최소한 메쏘드의 인자와 리턴타입을 알 수 있는 스텁(stub) 클래스는 존재해야만 컴파일해 볼 수 있다.

하지만 스텁 클래스를 만드는 것 자체가 상당한 디자인을 요한다. 특히 자바 같은 경우 클래스 인터페이스를 만드는 게 코딩의50% 이상이라고 말해도 과언이 아니다. 테스트 케이스 작성을 먼저하는 이유는 인터페이스를 고정하기 전에 클래스의 유스케이스를먼저 보겠다는 뜻인데, 이에 맞춰서 스텁을 제공하는 것은 고역인 셈이다.

이에 대한 대안으로 필자의 제안처럼 테스트 도구가 자동으로 인터페이스(스텁)를 만들어주는 방법이 있다. NextGen에 스텁 생성(Stub-generating) 모드라는 걸 작업하고 있다는데, 이런 종류의 프로젝트를 시작해 보는 것도 괜찮을듯 싶다.