제가 대학에서 컴퓨터 과학을 공부할 때, 프로그램을 작성하는 법은 참 많이 배웠지만, 제 기억으로는 누구도 디버깅에 대해서는 말해주지 않았습니다. 새로운 것을 창조하는 멋진 세상에 대해서는 들었지만 대부분의 시간을 타인의 코드를 이해하기 위해 쓰게 될 거라고는 듣지 못했습니다.

우리들 대부분은 프로그램을 만드는 걸 중요시하지만, 실제로는 프로그램을 처음 작성할 때보다 훨씬 더 많은 시간을 우리가(또는 타인이) 작성한 게 무엇인지, 어째서 오동작하는지를 이해하는데 씁니다.

디버깅은 무엇인가?

프로그램을 실행하기 전에는 모든 게 좋은 상태에 있습니다.

프로그램을 실행한 후에는 무엇인가 예상하지 못한 안 좋은 상태가 됩니다.

우리가 해야 할 일은 어느 지점부터 어긋났는지를 찾고 그것을 바로잡는 것입니다.

프로그래밍과 버그란 무엇인가?

기본적으로, 프로그래밍은 변수에 들어 있는 데이타들을 오가며 세상을 조금 변화시키는 것입니다.

프로그램의 각 단계마다 우리는 프로그램의 변수 안의 데이타를 변경하거나, "현실 세계"의 무언가(예를 들어 디스크나 스크린)를 변화시킵니다.

프로그램을 작성할 때 각 단계마다 다음을 고려하게 됩니다: 어떤 값이 어느 변수로 옮겨져야 하는가.

버그는 어느 변수에 X라는 값을 넣었다고 생각했으나 실제로는 Y가 들어가버린 경우입니다.

어느 시점엔가, 보통은 프로그램이 종료될 때, 프로그램이 올바르지 않은 값을 출력한 걸 보고 그 사실을 알게 됩니다.

프로그램이 실행되고 있는 도중에는 경고가 뜨거나 프로그램이 비정상적으로 종료되면서 버그가 드러날 수도 있습니다.

어떻게 디버그할 것인가?

프로그램을 디버그하는 가장 명확한 방법은 프로그램을 실행하고, 각 단계마다 모든 변수에 예상된 값이 들어있는지 확인하는 것입니다. 이것은 디버거를 사용하거나 출력문을 삽입하여 출력결과를 검사하는 식으로 할 수 있습니다.

Perl에는 강력한 명령행 디버거가 딸려 있습니다. 그것을 학습하는 것을 권장합니다만, 처음에는 다소 어려울지 모르겠습니다. Perl 내장 디버거의 기본 명령어를 보여주는 동영상을 준비하였습니다.

Komodo, EclipsePadre, the Perl IDE 등과 같은 통합 개발 환경에는 그래픽 인터페이스를 제공하는 디버거가 들어 있습니다. 차후에 그것들 중 일부를 설명하는 동영상을 제공하도록 하겠습니다.

출력문

많은 사람들은 코드에 print 문을 추가하는 고전적인 방법을 사용합니다.

컴파일과 빌드에 시간이 많이 걸리는 언어에서는 print 문을 사용하여 디버그하는 것은 좋지 않은 방법으로 생각됩니다. 그러나 큰 규모의 프로그램이라도 컴파일과 실행이 몇 초 안에 되는 Perl에서는 그렇지 않습니다.

print 문을 추가할 때는 출력할 값 앞뒤에 구분 문자를 붙이도록 합니다. 이렇게 하면 값의 시작 또는 끝 부분에 공백이 포함되어 있어서 문제가 되는 경우를 잡아낼 수 있습니다. 이런 것은 구분자가 없으면 알아채기 어렵습니다.

스칼라 값은 다음과 같은 식으로 출력할 수 있습니다:

print "<$file_name>\n";

여기서 좌우에 부등호를 붙임으로써 변수의 내용을 정확히 볼 수 있도록 하였습니다:

<path/to/file
>

만일 위와 같이 출력되었다면 $file_name 변수의 끝에 개행 문자가 붙어 있는 것을 바로 알 수 있습니다. 아마도 chomp를 호출하는 것을 잊었나 봅니다.

복잡한 자료 구조

아직 스칼라도 배우기 전이지만, 여기서는 일단 앞으로 뛰어넘어 더 복잡한 자료 구조의 내용을 출력하는 법을 보여드리도록 하겠습니다. 여러분이 Perl 튜토리알을 읽는 과정에 이 기사를 본 것이라면 이 부분은 건너뛰었다가 나중에 다시 와서 봐도 됩니다. 지금은 큰 의미가 없을 수 있으니까요.

그렇지 않다면, 계속 진행하겠습니다.

복잡한 자료 구조(레퍼런스, 배열, 해시)에 대해서는 Data::Dumper를 사용할 수 있습니다.

use Data::Dumper qw(Dumper);

print Dumper \@an_array;
print Dumper \%a_hash;
print Dumper $a_reference;

위 코드는 아래와 같은 형태로 출력할 것이고, 변수의 내용을 이해하도록 도와줄 것입니다. 그렇지만 변수 이름이 $VAR1$VAR2와 같이 포괄적으로 나옵니다.

$VAR1 = [
       'a',
       'b',
       'c'
     ];
$VAR1 = {
       'a' => 1,
       'b' => 2
     };
$VAR1 = {
       'c' => 3,
       'd' => 4
     };

변수의 이름을 출력하도록 다음과 같이 코드를 덧붙이는 것을 권장합니다:

print '@an_array: ' . Dumper \@an_array;

이제 다음과 같이 나옵니다:

@an_array: $VAR1 = [
        'a',
        'b',
        'c'
      ];

또는 Data::Dumper 를 다음과 같이 사용하여:

print Data::Dumper->Dump([\@an_array, \%a_hash, $a_reference],
   [qw(an_array a_hash a_reference)]);

이렇게 나오게 할 수도 있습니다:

$an_array = [
            'a',
            'b',
            'c'
          ];
$a_hash = {
          'a' => 1,
          'b' => 2
        };
$a_reference = {
               'c' => 3,
               'd' => 4
             };

자료 구조를 출력하는 더 나은 방법들이 있지만, 이 시점에는 Data::Dumper로 충분히 우리가 원하는 걸 얻을 수 있고, 게다가 이 모듈은 어떤 Perl 설치본에도 들어 있습니다. 다른 방법들에 대해서는 나중에 알아보도록 하겠습니다.