Одна функция выполняет одну задачу
Если функция выполняет несколько разных, слабо связанных друг с другом задач, подумайте о том, чтобы разбить эту функцию на несколько.
Имена функций должны содержать глагол
Наименования функций должны включать глагол, например «get_domain_name», или «crash_my_program».
Имена, заданные без учёта этого принципа, вроде «flat_components», могут быть истолкованны совершенно по разному, например как «get_flat_components», «set_flat_components», «update_flat_components», «remove_flat_components» или «add_flat_components».
Используйте устоявшиеся пары антонимов в именах функций
В книге Стива Макконелла «Совершенный код» приводятся устоявшиеся пары антонимов, рекомендуемые для использования в именах функций/методов, а именно:
add / remove, begin / end, create / destroy, first / last, increment / decrement, insert / delete, lock / unlock, min / max, next / prev, old / new, open / close, show / hide, source / target, start / stop, up / down.
Использование «несогласованных» пар глаголов вроде add / delete или insert / destroy вводит в заблуждение и усложняет анализ кода.
Имена private-функций начинаются с подчёркивания
Если в модуле присутствуют функции, предназначенные только для внутреннего использования, которые никогда не будут вызваны за пределами модуля (за исключением случая автоматического тестирования), можно предварять имена этих private-функций знаком подчёркивания. Пример: _do_some_private_actions.
Отступы и комментарии для функций
Функции отделены друг от друга минимум одной пустой строкой. Для каждой функции необходимо краткое описание того, что она делает:
# Получить имя домена по его id sub get_domain_name { … }
или так,
=item B<get_domain_name>($id)
Получить имя домена по его id
=cut sub get_domain_name { … }
Приём входных параметров функций
Параметры принимаются с использованием конструкции:
my ($param1, $param2) = @_;
Она должна располагаться в первой строке функции и отделяться пустой строкой от последующего кода. Этот вариант считается стандартным и должен применяться всегда, кроме описанных ниже исключений.
Возможно использование shift и pop в сложных случаях, где это обоснованно (т. е. требуется изменение @_, либо используется хитрая последовательность параметров): некоторые случаи использования AUTOLOAD, работы с коллбэками и т. п.
В случае переменного количества параметров, если количество и смысл последующих параметров может варьироваться в зависимости от значения предыдущих параметров, тоже допускается принимать эти первые по счёту параметры с помощью shift:
my $action = shift; my ($name, $value, $reason); ($name, $value) = @_ if $action eq 'new'; ($reason) = @_ if $action eq 'destroy';
Однако такие ситуации очень редко имеют весомое оправдание, как правило от них стоит избавляться, изменив интерфейс функции либо использую именованные параметры:
my ( $action, $params ) = @_; if ( $action eq 'new' ) { # работаем с $params->{name} и $params->{value} } elsif ( $action eq 'destroy') { # работаем с $params->{reason} }
Допускается работа с аргументами функции напрямую через $_[0], когда это явно требуется с точки зрения логики работы функции или производительности, например:
- функция работает с большими кусками данных и нужно избежать их копирования из переданных параметров во внутренние переменные;
- функции требуется изменять переданные в неё аргументы (например, функции декодирования, рекурсивного обхода структур данных).
Все случаи отклонения от стандартного вида приёма параметров должны иметь явное обоснование, которое желательно описать в комментарии.
Именованные аргументы принимаются следующим образом:
my %param = @_;
Документирование входных параметров функций
Если аргументы функции нетривиальны (их назначение и набор допустимых значений не очевидны из их названия и контекста), после описания функции добавляется строка пояснения по аргументам. Если какой-либо аргумент может принимать конечное дискретное множество значений — это множество также перечисляется в комментариях. Если используются именованные параметры — все возможные параметры также перечисляются в комментариях, обязательные параметры обозначаются звёздочкой:
# %param: action*, domain_name*, comment # action: new, renew, delete
Не более 3-х позиционных параметров у функций
Функция может принимать не более 2-х, максимум 3-х ПОЗИЦИОННЫХ аргументов. При большем количестве аргументов либо проводится рефакторинг с целью уменьшения количества входных параметров, либо используются именованные параметры:
my %param = @_;
Именованные параметры обязательно документируются.
Проверка аргументов
В случае использования именованных параметров, если есть как обязательные, так и необязательные параметры, желательно проверять наличие обязательных параметров. В случае их отсутствия — вызывать исключение с помощью Carp::confess (для получения stack backtrace) или Carp::croak. В случае использования позиционных параметров проверка наличия и корректности переданных аргументов также приветствуется.
Документирование выходных параметров функций
Если выходные параметры функции не очевидны / нетривиальны, особенно это касается возврата сложных структур данных, желательно их документировать (после описания входных параметров).
Возврат скаляра или списка, в зависимости от wantarray
Если функция возвращает список значений, но из возвращаемого списка часто может использовать только первое значение, желательно выдавать только первое значение или весь список в зависимости от контекста:
return wantarray ? (user_id, username) : user_id;