Руководство по оформлению кода на Перле

Автор оригинала: Steve Hay
  • Перевод
image

Конечно, у каждого программиста есть свои собственные предпочтения в отношении форматирования, но есть некоторые общие принципы, следование которым делает ваши программы легко читаемыми, понимаемыми и поддерживаемыми.

Главная фишка заключается в том, что ваши программы всегда должны запускаться с флагом -w. При необходимости, вы можете целенаправленно отключить это действие для конкретных участков кода через прагмы no warnings или переменную $^W. Так же, вы должны всегда запускать программы с использованием use strict, либо же четко понимать, почему вы этого не делаете. Прагмы use sigtrap и use diagnostics так же могут быть полезными.

Что касается эстетики оформления кода, то единственная вещь, о которой всерьез заботится Ларри, это то, что закрывающая фигурная скобка многострочного блока должна быть выровнена по вертикали с ключевым словом, начинающим всю конструкцию. Кроме того, у него есть другие предпочтения, которые не так серьезны:

  • Отступы в 4 колонки.
     
  • Открывающая фигурная скобка, по возможности, на одной строке с ключевым словом, иначе выровнена с ним по вертикали.
     
  • Пробел перед открывающей фигурной скобкой в многострочном блоке.
     
  • Однострочный блок может быть размещен на одной строке, включая фигурные скобки.
     
  • Перед точкой с запятой пробелы не пишутся.
     
  • Точка с запятой опускается в «коротких» однострочных блоках.
     
  • Пробелы вокруг большинства операторов.
     
  • Пробелы вокруг «сложных» конструкций (внутри фигурных скобок).
     
  • Пустые строки между частями кода, выполняющими разные задачи.
     
  • Неприжимающиеся else.
     
  • Между именем функции и открывающей скобкой пробелы не пишутся.
     
  • Пробелы после каждой запятой.
     
  • Длинные строки ломаются после операторов (исключая and и or).
     
  • После последней закрывающей скобки в строке должен быть пробел.
     
  • Выравнивайте по вертикали похожие элементы.
     
  • Опускайте избыточную пунктуации, если от этого не страдает ясность.

У Ларри есть обоснование для всех этих штук, но он не утверждает, что все рассуждают так же, как он.

Вот несколько других, более существенных вопросов оформления, о которых следует подумать:

  • Если вы МОЖЕТЕ сделать что-то определенным образом, это не значит, что вы ДОЛЖНЫ делать именно так. Перл спроектирован так, чтобы дать вам несколько способов сделать одно и то же, постарайтесь выбрать из этих способов более наглядный. Например, это:

    open(FOO,$foo) || die "Can't open $foo: $!";
    

    лучше, чем это:

    die "Can't open $foo: $!" unless open(FOO,$foo);
    

    потому, что второй вариант прячет основной смысл этого выражения в условии. С другой стороны,

    print "Starting analysis\n" if $verbose;
    

    лучше, чем

    $verbose && print "Starting analysis\n";


    

    потому, что суть тут не в том, набрал ли пользователь -v или нет
.

    Аналогично, если у оператора есть аргументы со значениями по умолчанию, это не значит, что нужно их использовать. Значения по умолчанию — для ленивых системных программистов, пишущих одноразовые программы. Если вы хотите, чтобы ваша программа была легко читаемой, подумайте об использовании аргументов.

    Опять же, то, что вы МОЖЕТЕ опустить скобки во многих местах, вовсе не означает, что это следует делать. Сравните:

    return print reverse sort num values %array;

    return print(reverse(sort num (values(%array))));

    

    Если сомневаетесь — ставьте скобки. По крайней мере, это позволит какому-нибудь бедолаге потыкать клавишу % в vi.

    Даже если вы не сомневаетесь, подумайте о психическом равновесии человека, который будет поддерживать код после вас, и который, вероятно, поставит скобки в неправильном месте.
     
  • Не делайте бессмысленных проходов по циклу сверху до низу, ведь Перл предоставляет оператор last, позволяющий выйти в середине. Просто сделайте небольшой «недоотступ», чтобы показать это более наглядно:

    LINE:

        for (;;) {

            statements;

          last LINE if $foo;

            next LINE if /^#/;

            statements;

        }

  • Не бойтесь использовать метки циклов — они там для удобства, а так же для прерывания многоуровневых циклов. Смотрите предыдущий пример.
     
  • Избегайте использования grep(), map() или `обратных кавычек` в пустом контексте, когда вы просто выбрасываете возвращаемые ими значения. Все эти функции возвращают значения, так что задействуйте их. Либо же используйте цикл foreach() или функцию system().
     
  • Для переносимости, если используются какие-то функции, которые могут быть не реализованы на некоторых машинах, тестируйте эти конструкции в eval, чтобы увидеть возникающие ошибки. Если вы знаете, в какой версии или в каком патче реализована нужная функция, проверяйте $] ($PERL_VERSION в модуле English), чтобы увидеть, есть ли она там. Модуль Config так же позволяет выяснять значения, определенные программой Configure при установке Перла.
     
  • Выбирайте запоминающиеся идентификаторы. Если вы не можете вспомнить, что означает ваша напоминалка — у вас проблема.
     
  • Если короткие идентификаторы типа $gotit вполне приемлемы, то в длинных идентификаторах следует использовать подчеркивания для разделения слов. Обычно гораздо проще читать $var_names_like_this, чем $VarNamesLikeThis, особенно тем, для кого английский язык не родной.

    Названия пакетов имеют некоторые исключения из этого правила. Перл неофициально резервирует названия модулей в нижнем регистре для прагм, таких как integer или strict. Другие модули должны начинаться с большой буквы и использовать смешанный регистр, по возможности без подчеркиваний, из-за ограничений примитивных файловых систем, в которых названия файлов, представляющих модули, должны вписываться в несколько байт.
     
  • Вы можете счесть полезным использование регистра для обозначения области видимости или назначения переменной. Например:

    $ALL_CAPS_HERE   только константы (остерегайтесь конфликта со встроенными переменными Перла)

    $Some_Caps_Here  глобальные и статические переменные
    
$no_caps_here    переменные, ограниченные областью видимости
    

    Названия функций и методов, похоже, лучше всего работают в нижнем регистре. Например, $obj->as_string().

    Вы можете использовать ведущее подчеркивание для указания того, что эта переменная или функция не должны использоваться за пределами пакета, в котором они объявлены.
     
  • Если у вас есть реально навороченное регулярное выражение, используйте модификатор /x и добавьте немного пробелов, чтобы выражение выглядело не так страшно. Не используйте слеш в качестве разделителя, если само регулярное выражение содержит слеши или обратные слеши.
     
  • Используйте новые операторы and и or чтобы избавиться от слишком большого количества скобок в списочных операторах, а так же для того, чтобы не усложнять чтение пунктуационными операторами вроде && и ||. Вызывайте ваши подпрограммы так же, как если бы они были функциями или списочными операторами, чтобы избавиться от лишних скобок и амперсандов.
     
  • Используйте here-документы вместо повторного написания print().
     
  • Выравнивайте похожие элементы по вертикали, особенно в конструкциях, которые все равно слишком длинные, чтобы поместиться на одной строке.

    $IDX = $ST_MTIME;
    
$IDX = $ST_ATIME       if $opt_u;
    
$IDX = $ST_CTIME       if $opt_c;

    $IDX = $ST_SIZE        if $opt_s;
    
    

mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!";
    
chdir($tmpdir)      or die "can't chdir $tmpdir: $!";
    
mkdir 'tmp',   0777 or die "can't mkdir $tmpdir/tmp: $!";

    

  • Всегда проверяйте код возврата системных вызовов. Хорошее сообщение об ошибке должно отправляться в STDERR и включать указание на то, какая программа вызвала проблему, какой системный вызов и с какими аргументами был выполнен с ошибкой, а так же (ОЧЕНЬ ВАЖНО), должно содержать стандартное системное сообщение о том, что именно пошло не так. Вот простой, но исчерпывающий пример:

    opendir(D, $dir)     or die "can't opendir $dir: $!";

    
  • Выравнивайте по вертикали транслируемые символы, когда это имеет смысл:

    tr [abc]

       [xyz];

    
  • Подумайте о повторном использовании. Зачем тратить силу ума на разовый выхлоп, если можно сделать что-то, что будет работать снова и снова? Постарайтесь обобщить ваш код. Постарайтесь написать модуль или класс. Постарайтесь сделать работу вашего скрипта чище с помощью use strict и use warnings (или -w). Постарайтесь поделиться вашим кодом. Постарайтесь изменить ваш взгляд на мир. Постарайтесь… а, ладно.
     
  • Попробуйте документировать код и использовать формат Pod на постоянной основе. Тут есть несколько общих соглашений:

    • Используйте C<> для названий функций, переменных и модулей (и вообще всего, что можно считать частью кода, типа дескрипторов файлов или специальных значений). Обратите внимание, что названия функций оказывается легче читать, если у них есть скобки после имени, вроде такого — function().
       
    • Используйте B<> для названий команд, таких как cat или grep.
       
    • Используйте F<> или C<> для названий файлов. F<> должен быть единственным Pod-кодом для имен файлов, но большинство Pod-конвертеров отображают его курсивом, из-за чего пути в Unix и Windows, содержащие прямые и обратные слеши, могут выглядеть плохо читаемыми и использование C<> выглядит предпочтительнее.

  • Будьте последовательными.
     
  • Будьте клёвыми.
     
Поделиться публикацией

Похожие публикации

Комментарии 32

    0
    Более полный и развёрнутый вариант оформления можно почитать тут www.reg.ru/coding_standards#code
      +1
      1. Там не про Перл, там про все подряд.
      2. Там некий корпоративный стандарт Рег.ру, а не CPAN'овский стандарт де-факто от одного из мейнтейнеров Перла. Впрочем, в перловой части стандарт Рег.ру основан на CPAN'овском.
      0
      Спасибо за статью.
      Большую часть этих требований может выполнить perltidy без ручного редактирования кода.
      Например, вот так это работает в vim
        0
        Да, конечно. Но это же не вместо perltidy, это первоисточник, на который опирается perltidy:)
        0
        Удобно поставить Perl::Tidy с конфигом perl best practice хуком на коммит в репозиторий.
          0
          Меня некоторые правки, вносимые perltidy, не устраивают. Вы, случаем, не знаете, как сказать perltidy, чтобы он «не делал ничего, что не сказано делать явным образом через параметры»?
            0
            Есть # теги, между которыми он не форматирует.
            Вообще там все настраивается, что именно вас не устраивает в форматировании?
              0
              > Есть # теги, между которыми он не форматирует.

              Да, но это решение для локальных участков. Я не хочу заключать в эти теги весь код.

              > Вообще там все настраивается, что именно вас не устраивает в форматировании?

              Не могу огласить весь список. Для этого мне придется засесть на месяц и перебрать все возможные комбинации. Я хочу отключить всё, а потом включать то, что мне надо.
                0
                Ну так наверное не получится.
                Вообще лучше следовать общим стандартам, которые perltidy имплементирует.
                Тогда и с чужим кодом проблем не будет.
                  0
                  Не готов на это пойти так вот сразу:)

                  К тому же, ведь и сам perltidy позволяет включать/выключать всяко-разно, так что вряд ли можно говорить о каком-то одном общем стандарте. Вариаций хватает.
                    0
                    Да, там все настраивается, но есть признанный стандарт Дамиена Конвея — perl best practice, там все очень логично.

                    Набор этих сеттингов включается одной опцией --pbp.

                    Как ни крути, стандарты важны, особенно в таких рутинных задачах, как форматирование кода.
                      0
                      PBP, конечно, наше всё, но всё-равно, не готов так вот взять и форматнуть весь код. Уж слишком много perltidy вносит правок, и часть из них мне не нравится по религиозным причинам.

                      А отключить конкретные правки затруднительно, потому что, во-первых, так сразу не сообразишь, какой именно опцией отключается эта правка, а во-вторых, нет гарантии, что еще чего-нибудь не вылезет. В итоге приходится вручную перепроверять, что там perltidy натворил, а это как-то глупо…

                      Не понимаю, почему в нем нет опции «отключить все умолчания».
                        0
                        Да вам надо набраться сил и один раз перейти.
                        Смысл руками отступы форматировать и пробелы расставлять.

                        Вот мой конфиг, как стимул :-):

                        --perl-best-practices --tight-secret-operators --continuation-indentation=2 --maximum-line-length=0 --format-skipping --converge --nostandard-output
                          0
                          Зачем у Вас --format-skipping и --nostandard-output? Они же и так по умолчанию включены.

                          Правильно ли я понимаю опцию --converge? Она гарантирует, что сколько раз потом не прогоняй, результат будет тот же?
                            0
                            Для наглядности, что они включены.

                            В общем да.
                      0
                      Кстати, форматтера, подобного Perl::Tidy не встречал ни в одном скриптовом языке, везде что-то есть, но кривое, форматирует по-разному.

                      Perl::Tidy приводит огромные скрипты к одному знаменателю, всегда однообразно, в привычный вид, это реально очень упрощает жизнь. Отлично форматирует структуры данных.

                      Можно использовать знак коммента, если где-то вам нужен перевод строки, а тайди все объединяет в одну строку и настроить нельзя.

                      Еще могу посоветовать Perl::Critic к обязательному использованию. Тоже помогает сформировать стиль кодирования, да и много узнаешь о лучших практиках написания кода, когда начинаешь пользоваться.

                      Мне это очень помогло в свое время.
                        0
                        Перлкритик да, заставляю себя выполнять третий уровень. На первый и второй уровни у меня пока энтузиазма не хватает:)
                          0
                          Первый / второй — я тоже не выполняю, там ничего критичного нет.
                          У меня со временем появился конфиг правил, расставил уровни для важных для меня policy, что-то отключилось, что-то доконфигурировалось.
                0
                #<<, #>>
                  0
                  Это не то. Это полностью отключит форматирование.
              0
              At the very least it will let some poor schmuck bounce on the % key in vi (прим. пер. — не смог перевести, вроде это какая-то шутка про редактор vi).
              В vi клавиша % (Shift+5) выполняет переход от открывающей скобки к соответствующей ей закрывающей, и наоборот.
                0
                Ок, уже лучше. А «will let some poor schmuck» как перевести?
                  +1
                  Если верить Лингве, слово «schmuck» может выражать довольно широкий спектр отрицательных значений, от лёгкого недовольства («зануда») до резкого неприятия и осуждения (мерзавец, тупица, олух). Поскольку это не художественная литература, я бы особо заморачиваться не стал и перевёл как-нибудь так:
                  Если сомневаетесь — ставьте скобки. По крайней мере, это позволит какому-нибудь дурачку потыкать в клавишу % в vi.
                  Можно заменить «дурачка» на «беднягу», если боитесь минусов в карму от вимеров, не заметивших, что это перевод. :-)
                    0
                    Ага, спасибо. Поправил в статье.
                0
                По-моему, рекомендация про `-w` устарела. Не сталкиваюсь последнее время с тем что его включают. Вместо этого пишут 'use warnings' в свойм коде. Чужой код, если без use warnings — либо так надо, либо его не нужно использовать.
                  0
                  Так это одно и то же. Но да, я тоже пишу «use warnings».
                    0
                    Отличие в том что -w включается для всего процесса. Для всех-всех 3rd party модулей. А use warnings — только lexical scope. Ну и ещё вроде есть мелкие отличия.
                      0
                      Да, точно. Но тогда, наверное, нельзя утверждать, что -w устарело.
                        0
                        -w не устарело, но не позволяет гибко управлять варнингами, поэтому не универсально.
                          0
                          Не -w устарело, а рекомендация его использовать, как часть coding standard, ИМХО. Редко вижу последние N лет.
                    0
                    Меня смущает недоотступ в last. Зачем?
                      0
                      Ну как же — для визуального выделения команды, которая прерывает цикл.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое