=encoding UTF-8

=head1 NAME

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

=head1 ВВЕДЕНИЕ

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

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

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

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

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

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

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

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

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

=over 4

=item *

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

=item *

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

=back

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

=over 4

=item *

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

=item * 

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

=item *

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

=item *

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

=back

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

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

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

=head2 OO или не OO?

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

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *


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

=item *

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

=item *

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

=item *

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

=back

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

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

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

=over 4

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

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

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

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

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

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

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

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

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

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

чем

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

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

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

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

    $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)
в значительной степени вопрос личного стиля.

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

=back

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

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

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

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

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

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=back

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


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

=head2 POD

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

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

=over 4

=item * 

ИМЯ (NAME)

=item *

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

=item *

ОПИСАНИЕ (DESCRIPTION)

=item *

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

=item *

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

=item *

АВТОР (AUTHOR)

=item *

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

=item *

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

=back

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

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

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

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

=over 4

=item perl Makefile.PL

=item make

=item make test

=item make install

=back

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

=over 4

=item perl Build.PL

=item perl Build

=item perl Build test

=item perl Build install

=back

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

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

=head2 Нумерация версий (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.)

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

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

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

=over 4

=item *

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

=item *

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

=item *

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

=item *

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

=back

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

=over 4

=item L<perlstyle>

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

=item L<perlnewmod>

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

=item L<perlpod>

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

=item L<podchecker>

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

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

L<ExtUtils::MakeMaker>, L<Module::Build>

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

L<Test::Simple>, L<Test::Inline>, L<Carp::Assert>, L<Test::More>, L<Test::MockObject>

=item http://pause.perl.org/

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

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

=back

=head1 АВТОР

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

=head1 ПЕРЕВОДЧИКИ
 
=over
 
=item * Николай Мишин C<< <mi@ya.ru> >>
 
=back
