Когда я учился информатике в университете, нам много говорили о написании программ, но, насколько я помню, никто не упоминал об отладке. Мы узнали о прекрасном мире создания нового, но никто не сказал нам, что бо́льшую часть времени нам придется тратить на то, чтобы понять чужой код.

Оказывается, что, хотя мы придаем больше значения написанию программ, на деле гораздо больше времени занимают попытки понять, что мы сами (или кто-то другой) написали и почему это работает не так, как надо.

Что такое отладка?

До запуска программы все было в известном правильном состоянии.

После запуска программы что-то перешло в неожиданное и неправильное состояние.

Задача состоит в том, чтобы выяснить, где что-то пошло не так, и исправить это.

Что такое программирование и что такое баг?

По сути, программирование - это небольшое изменение мира посредством изменения данных в переменных.

На каждом этапе программы мы меняем некоторые данные в переменной программы, или что-то в "реальном мире". (Например, на диске или на экране.)

Когда вы пишете программу, вы продумываете каждый шаг: какое значение в какую переменную должно быть помещено.

Баг - это случай, когда вы думали, что поместили значение X в какую-то переменную, а на самом деле туда попало значение Y.

В какой-то момент, обычно в конце программы, вы понимаете это, так как программа выдает неверный результат.

Во время исполнения программы это может обнаружиться в виде предупреждения или ненормального завершения программы.

Как отлаживать программы?

Самый прямой путь отладки программы - запустить ее, и на каждом шаге проверять, все ли переменные содержат предполагаемые значения. Это можно либо сделать с помощью отладчика, либо вставить в программу выражения print и после ее выполнения проверять вывод.

В Perl входит очень мощный отладчик для командной строки. Мы рекомендуем изучить его, хотя он может поначалу немного напугать. Я подготовил видео, в котором показываю основные команды встроенного отладчика Perl.

IDE, такие как Komodo, Eclipse и Padre, the Perl IDE, включают графические отладчики. Когда-нибудь я сделаю видео про какой-нибудь из них.

Выражения вывода

Многие люди используют старинную технику добавления в код выражений вывода.

В языках, где компиляция и сборка занимает много времени, использование выражений вывода для считается плохим способом отладки. Но не в Perl, где даже большие приложения компилируются и запускаются в считанные секунды.

Добавляя выражения вывода, нужно позаботиться о помещении разделителей вокруг значений. В таком случае вы заметите пробелы в начале и в конце, которые могут вызывать проблемы. Их сложно увидеть без разделителей:

Скаларные значения можно выводить так:

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. Другие способы мы обсудим позднее.