The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

perlmodstyle - стиль написания модулей на Perl

ВВЕДЕНИЕ

Этот документ пытается описать "наилучшие практики" ("best practice") Perl-сообщества для написания Perl модулей. Она расширяет рекомендации, найденные в perlstyle , который должен быть внимательно рассмотрен перед чтением этого документа.

Хотя этот документ призван быть полезным для всех авторов модулей, в частности он направлен на авторов, которые хотят опубликовать свои модули на CPAN.

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

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

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

В первом разделе настоящего документа приводится подробный перечень; в последующих разделах приводится более подробное обсуждение пунктов этого списка. В заключительном разделе "Общие Ловушки" ("Common Pitfalls"), описываются некоторые самые популярные ошибки, сделанные авторами CPAN.

БЫСТРЫЙ ЧЕКЛИСТ

Для более подробной информации по каждому пункту в этом чеклисте, смотрите ниже.

Прежде чем ты начнешь

  • Не изобретайте колесо (Don't re-invent the wheel)

  • Создайте патч, расширение или подкласс существующего модуля там, где это возможно (Patch, extend or subclass an existing module where possible)

  • Делайте одну вещь и делайте ее хорошо

  • Выберите подходящее имя

API - интерфейс модуля

  • API должен быть понятным среднего программиста

  • Простые методы для решения простых задач

  • Разделяйте функции по своему результату

  • Последовательное наименование подпрограмм или методов

  • Используйте именованные параметры (хэш-или hashref) при наличии более двух параметров

Стабильность

  • Убедитесь, что ваш модуль работает под use strict и -w

  • Стабильные модули должны поддерживать обратную совместимость

Документация

  • Пишите документацию в POD

  • Назначения документа, сфера применения и целевые приложения (Document purpose, scope and target applications)

  • Документируйте каждый публично доступный метод или подпрограмму, в том числе параметры и возвращаемые значения

  • Приведите примеры использования в документации

  • Предоставьте файл README и, возможно, также заметки о выпуске(release notes), изменения(changelog) и т.д.

  • Обеспечить ссылки на дополнительную информацию (URL, адрес электронной почты)

Соображения о релизе (Release considerations)

  • Укажите зависимости в Makefile.PL или Build.PL

  • Указывайте версию Perl в кляузе use

  • Включите в ваш модуль тесты

  • Выберите разумную и последовательную схему нумерации версий (X.YY - это общая схема нумерации модулей Perl)

  • Увеличивайте номер версии для каждого изменения, независимо от того, насколько мал

  • Упакуйте модуль, используя команду "make dist"

  • Выберите соответствующую лицензию (GPL/Artistic будет хорошим значением по умолчанию)

ПЕРЕД НАЧАЛОМ НАПИСАНИЯ МОДУЛЯ

Старайтесь не кидаться с головой в разработку своего модуля, не тратя некоторого времени на обдумывание в первую очередь. Небольшая предусмотрительность может сэкономить вам огромное количество усилий в дальнейшем. ( A little forethought may save you a vast amount of effort later on.)

Был ли было сделано раньше?

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

Хорошее места, чтобы искать уже существующие модули будет http://search.cpan.org/ и спрашивайте на modules@perl.org

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

Сделайте одну вещь и сделайте это хорошо

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

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

Плохой пример:

"FooBar.pm обеспечивает реализацию протокола FOO в соответствии со стандартом BAR ".

Хороший пример:

"Foo.pm обеспечивает реализацию протокола Foo. Bar.pm реализует соответствующий протокол BAR ".

Это означает, что если разработчику необходим только модуль для стандарта BAR, он не должен для этого быть вынужден устанавливать библиотеку также и для FOO.

Какое будет имя?

Убедитесь, что вы выбрали подходящее имя для вашего модуля на ранних стадиях. Это поможет людям находить и помнить выш ​​модуль и сделает программирование с вашим модулем более интуитивным.

При выборе названия вашего модуля , необходимо учитывать следующее:

  • Будьте описательными ( т.е. точно описывайте цель модуля ) .

  • Согласовывайте имя с существующими модулями.

  • Имя отражает функциональность модуля , а не его реализацию.

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

Вы должны связаться с modules@perl.org, чтобы спросить их о вашем имени перед публикацией модуля. Вы должны также попытаться спросить людей, которые уже знакомы с областью применения модуля, а также исследовать систему наименований моделей CPAN. Авторы подобных модулей , или модули с аналогичными характеристиками имена , могут быть хорошим местом для начала.

ПРОЕКТИРОВАНИЕ И НАПИСАНИЕ ВАШЕГО МОДУЛЯ

Соображения по конструкции(дизайну) модуля и его кодирования:

OO или не OO?

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

В Perl Best Practices (copyright 2004, Published by O'Reilly Media, Inc.) Дамиан Конвей предоставляет список критериев, который используется при принятии решения, подходит ли OO для вашей проблемы:

  • Система разрабатывается большая, или, вероятно, станет большой.

  • Данные могут быть объединены в очевидные структуры, особенно, если есть большое количество данных в каждом агрегате.

  • Различные типы совокупности данных образующие естественную иерархию, облегчают использование наследования и полиморфизма .

  • У вас есть часть данных, к которым применяются много различных операций.

  • Вы должны выполнить те же самые общие операции со связанными типами данных, но с небольшими изменениями в зависимости от их конкретного типа.

  • Вполне вероятно, что позже вам придется добавлять новые типы данных.

  • Типичные взаимодействия между частями данных лучше всего представить в виде операторов.

  • Реализация отдельных компонентов системы, скорее всего, будет изменена с течением времени.

  • Дизайн системы уже объектно-ориентированный.

  • Большое количество других программистов будут использовать ваши модули.

Подумайте тщательно о том, подходит ли OO для вашего модуля. Беспричинным результатом объектной ориентации будет сложное API, которое будет трудно для среднего пользователя для понимания или использования.

Проектирование вашего API

Ваши интерфейсы должны быть понятны средним Perl программистам. Следующие рекомендации могут помочь вам определить, является ли ваш API достаточно простым:

Напишите простые процедуры, чтобы делать простые вещи.

Лучше иметь много простых процедур, чем немного, но очень больших и сложных монолитов. Если ваша подпрограмма существенно меняет свое поведение на основе своих аргументов, то это признак того, что вы должны иметь две (или более ) отдельные подпрограммы.

Создавайте отдельные функции для потока вывода (output).

Возвращайте результаты в наиболее общей форме насколько это возможно и позволяйте пользователю выбирать, как использовать их. Наиболее общая форма - это,возможно , как правило, структура данных Perl, которая затем может быть использована для создания текстового отчета, HTML, XML, запроса к базе данных , или то, что требуется пользователям.

Если процедура перебирает какой-то список (например, список файлов или записей в базе данных), вы можете рассмотреть вопрос о предоставлении обратного вызова так, чтобы пользователи могли манипулировать каждым элементом списка в свою очередь. File::Find дает пример этого с его find(\&wanted, $dir) синтаксисом.

Обеспечьте разумные сокращения и значения по умолчанию.

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

Соглашения об именовании

Ваше именование должно быть последовательным. Например, лучше иметь:

        display_day();
        display_week();
        display_year();

чем

        display_day();
        week_display();
        show_year();

Это в равной степени относится к именам методов, именам параметров, и всего остального, которое видно пользователю (и к большинству вещей , которые этим не являются! )

Передача параметров

Используйте именованные параметры . Проще использовать хэш следующим образом:

    $obj->do_something(
            name => "wibble",
            type => "text",
            size => 1024,
    );

... чем иметь длинный список безымянных параметров таких, как этот:

    $obj->do_something("wibble", "text", 1024);

В то время как список аргументов может прекрасно работать с одним, двумя или даже с тремя аргументами, все больше аргументов становятся трудными для запоминания , и трудными для управления автором модуля. Если вы хотите добавить новый параметр, вам придется добавить его в конец списка для обратной совместимости, и это, вероятно, сделает ваш список заказа неинтуитивным. Кроме того, если многие элементы могут быть неопределенными вы можете увидеть следующие непривлекательные вызовы методов:

    $obj->do_something(undef, undef, undef, undef, undef, undef, 1024);
    

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

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

Использование хэш-ключей, начинающихся с дефиса (-name) или полностью в верхнем регистре (NAME) является пережитком старых версий Perl, в котором обычные нижние строки могли быть не правильно обработаны с помощью оператора =>. В то время как некоторые модули оставляют переменные в верхнем регистре или аргументы с дефисом (-) по историческим причинам или как вопрос личного стиля, большинству новых модулей следует использовать простые нижний регистр для ключей. Что бы вы ни выбрали, будьте последовательны!

Строгость и предупреждения (Strictness and warnings)

Ваш модуль должен успешно работать под прагмой use strict и должен работать без создания каких-либо предупреждений. Ваш модуль должен также обрабатывать проверки заразности (taint-checking), где это уместно, хотя это может вызвать трудности во многих случаях.

Обратная совместимость

Модули, которые являются "стабильными"("stable") не должны нарушать обратную совместимость по крайней мере без длительного переходного этапа и главного (major) изменения в номере версии.

Обработка ошибок и сообщения

Когда ваш модуль обнаружил ошибку он должен сделать одно или более из следующего:

  • Возврат неопределенного(undefined) значения.

  • установите $Module::errstr или подобное имя (errstr как общее имя для ошибок, как это сделано в моделу DBI и других популярных модулях; если вы выберете другое имя, то не забудьте это понятно задокументировать).

  • Используйте warn() или carp() сообщение для посылки в STDERR.

  • Используйте croak() только тогда, когда ваш модуль абсолютно не может понять, что делать. (croak() - это лучшая версия die() для использования внутри модулей , который передает свои ошибки с точки зрения вызывающей процедуры (caller). Смотри Carp для деталей по croak(), carp() и другие полезные процедуры.)

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

Настраиваемая обработка ошибок может быть очень полезной для пользователей. Можно предлагать выбор уровней для предупреждений(warning) и отладочных(debug) сообщений, возможность отправлять сообщения в отдельный файл, способ задания процедур обработки ошибок , или другие подобные функции. Убедитесь, что по умолчанию все эти параметры применяются в обычном использования.

ДОКУМЕНТИРОВАНИЕ ВАШЕГО МОДУЛЯ

POD

Ваш модуль должен включать в себя документацию, направленную на разработчиков Perl. Вы должны использовать перловую "обычную старую документацию" ("plain old documentation) (POD) для общей технической документации, хотя вы можете написать дополнительную документацию (технические документы(white papers), учебные пособия(tutorials) и т.д.) в каком-то другом формате. Вы должны охватывать следующие темы:

  • Краткое описание(synopsis) того, для чего нужен модуль

  • Цель, сфера применения(scope) и целевые приложения(target applications) модуля

  • Использование каждого публично доступного метода или подпрограммы, в том числе его параметры и возвращаемые значения

  • Примеры использования

  • Источники дополнительной информации

  • Контактный адрес электронной почты автора/сопровождающего(maintainer)

Уровень детализации в документации модуля Perl? как правило, идет от менее до более подробного. Ваш раздел СИНТАКСИСА(SYNOPSIS) должен содержать минимальный пример использования (возможно это всего лишь одна строка кода, пропустить необычные случаи использования или что-нибудь не нужное большинству пользователей); ОПИСАНИЕ(DESCRIPTION) должно описывать ваш модуль в широком смысле, как правило, в всего в нескольких абзацах; более подробное описание процедур или методов работы модуля, длинные примеры кода, или другой углубленный материал должен быть приведен в последующих разделах.

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

Рекомендуемый порядок разделов в документации модуля Perl является:

  • ИМЯ (NAME)

  • СИНТАКСИС (SYNOPSIS)

  • ОПИСАНИЕ (DESCRIPTION)

  • Один или несколько разделов или подразделов, дающие более подробную информацию о присутствующих методах и процедурах и может быть любая другая подходящая информация.

  • ОШИБКИ/ПРЕДОСТЕРЕЖЕНИЯ/ и т.д. (BUGS/CAVEATS/etc)

  • АВТОР (AUTHOR)

  • СМОТРИТЕ ТАКЖЕ (SEE ALSO)

  • Авторское право и лицензии (COPYRIGHT and LICENSE)

Держите документацию рядом с кодом, который вы документируете ( "инлайн" документация). Включите POD для данного метода прямо над этим методом. Это облегчает поддержание актуальности документации, и позволяет избежать необходимости документировать каждый фрагмент кода дважды (один раз в POD и один раз в комментариях).

README, INSTALL, примечания к выпуску(release notes), записи изменений (changelogs)

Ваш модуль должен также включать файл README, описывающий модуль и дающий указатели на дополнительную информацию (веб-сайт, электронную почту автора).

Такжен должен быть включен файл INSTALL, который должен содержать простую инструкцию установки. При использовании ExtUtils::MakeMaker это будет так:

perl Makefile.PL
make
make test
make install

При использовании Module::Build это обычно будет:

perl Build.PL
perl Build
perl Build test
perl Build install

Заметки о выпуске(Release notes) или записи изменений(changelogs) следует создавать для каждого выпуска(release) вашего программного обеспечения, описывающее видимые пользователю изменения в вашем модуле, в терминах понятны пользователю.

РАССМОТРЕНИЕ ВЫПУСКА (RELEASE CONSIDERATIONS)

Нумерация версий (Version numbering)

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

Наиболее распространенная схема нумерации версий CPAN выглядит так:

    1.00, 1.10, 1.11, 1.20, 1.30, 1.31, 1.32

Верный номер версии CPAN - это число с плавающей точкой, по крайней мере 2 цифры после запятой. Вы можете проверить, соответствует ли он CPAN с помощью

    perl -MExtUtils::MakeMaker -le 'print MM->parse_version(shift)' 'Foo.pm'

Если вы хотите выпустить 'бету' или 'альфу'-версию модуля, но не хотите, чтобы CPAN.pm отображал его как самый последний, используйте '_' после номера обычной версии и еще минимум две цифры, например. 1.20_01. Если вы делаете это, рекомендуется следующая идиома:

  $VERSION = "1.12_01";
  $XS_VERSION = $VERSION; # нужен только, если у вас есть XS-код (only needed if you have XS code)
  $VERSION = eval $VERSION;

С помощью этого трюка MakeMaker будет читать только первую строку и таким образом читать подчеркивание, в то время как интерпретатор perl будет выполнять(evaluate) $VERSION и преобразовывать строку в число. Более поздние операции, которые используют $VERSION, как число, будет иметь возможность сделать это без предупреждение о том, что $VERSION не является числом.

Никогда не выпускайте ничего (даже патч с одним словом документации) без увеличения номера версии. Патч даже и измененным одним словом должен приводить к изменению версии на уровне полуминорной версии (sub-minor level). (Even a one-word documentation patch should result in a change in version at the sub-minor level.)

Требования (Pre-requisites)

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

Наиболее важно выбрать модули, которые настолько стабильны, насколько это возможно. В порядке предпочтения:

  • Модули ядра Perl (Core Perl modules)

  • Стабильные модули CPAN (Stable CPAN modules)

  • Нестабильные модули CPAN (Unstable CPAN modules)

  • Модули, недоступные в CPAN (Modules not available from CPAN)

Укажите требования к версии для других модулей Perl в предварительных условиях (pre-requisites) в Makefile.PL или Build.PL.

Обязательно укажите требования к версии Perl как в Makefile.PL, так и в Build.PL require 5.6.1 или аналогичный. См. Раздел use VERSION для "require" in perlfunc.

Тестирование

Все модули должны быть протестированы перед распространением (с использованием "make disttest"), и тесты также должны быть доступны для людей, устанавливающих модули (с помощью "make test"). Для Module::Build вы должны использовать эквивалент make test такой как perl Build test.

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

Полезные модули, которые помогут вам писать тесты (с минимальным воздействием на ваш процесс разработки или ваше время), включают Test::Simple, Carp::Assert и Test::Inline. Для более сложных тестовых наборов( test suites) есть Test::More и Test::MockObject.

Пакетизация (Packaging)

Модули следует упаковывать с использованием одного из стандартных инструментов упаковки(packaging tools). В настоящее время у вас есть выбор между ExtUtils::MakeMaker и более независимым от платформы модулем Module::Build, что позволяет устанавливать модули последовательно. При использовании ExtUtils::MakeMaker вы можете использовать "make dist" для создания своего пакета. Существуют инструменты, которые помогут вам создать свой модуль в стиле MakeMaker. К ним относятся ExtUtils::ModuleMaker и h2xs. См. Также perlnewmod.

Лицензирование

Убедитесь, что ваш модуль имеет лицензию, и что полный текст её включен в дистрибутив (если только он не является общим(it's a common one), и в условиях лицензии не требуется включать его).

Если вы не знаете, какую лицензию использовать, двойное лицензирование под лицензиями GPL и Artistic (то же самое, что и сам Perl) - хорошая идея. См. perlgpl и perlartistic.

РАСПРОСТРАНЕННЫЕ ОШИБКИ (COMMON PITFALLS)

Изобретение колеса (Reinventing the wheel)

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

Попытка сделать слишком много

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

Несоответствующая документация

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

Учебники, документация конечного пользователя, научные статьи, часто задаваемые вопросы и т. не подходят в основной документации модуля. Если вы действительно хотите их написать, включите их в качестве суб-документов, таких как My::Module::Tutorial и My::Module::FAQ, и укажите ссылку в разделе СМОТРИТЕ ТАКЖЕ(SEE ALSO) основной документации.

СМОТРИТЕ ТАКЖЕ

perlstyle

Общее руководство по стилю Perl разработки

perlnewmod

Как создать новый модуль

perlpod

документация POD

podchecker

Проверка корректности вашего POD

Инструменты создания модулей (Packaging Tools)

ExtUtils::MakeMaker, Module::Build

Инструменты тестирования

Test::Simple, Test::Inline, Carp::Assert, Test::More, Test::MockObject

http://pause.perl.org/

Сервер загрузки Perl.(Perl Authors Upload Server. - PAUSE) Содержит ссылки на информацию для авторов модулей.

Любая хорошая книга по разработке программного обеспечения

АВТОР

Kirrily "Skud" Robert <skud@cpan.org>

ПЕРЕВОДЧИКИ

  • Николай Мишин <mi@ya.ru>