Функции
1. Одна функция выполняет одну задачу
Если функция выполняет несколько разных, слабо связанных друг с другом задач, подумайте о том, чтобы разбить эту функцию на несколько.
2. Имена функций должны содержать глагол
Наименования функций должны включать глагол,
например «get_domain_name
», или
«chash_my_program
».
Имена, заданные без учёта этого принципа, вроде
«flat_components
»,
могут быть истолкованны совершенно по разному, например как
«get_flat_components
»,
«set_flat_components
»,
«update_flat_components
»,
«remove_flat_components
» или
«add_flat_components
».
3. Используйте устоявшиеся пары антонимов в именах функций
В книге Стива Макконелла «Совершенный код» приводятся устоявшиеся пары антонимов, рекомендуемые для использования в именах функций/методов, а именно:
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 вводит в заблуждение и усложняет анализ кода.
4. Имена private-функций начинаются с подчёркивания
Если в модуле присутствуют функции, предназначенные только
для внутреннего использования, которые никогда не будут
вызваны за пределами модуля (за исключением случая автоматического
тестирования), можно предварять имена этих private-функций
знаком подчёркивания. Пример: _do_some_private_actions
.
5. Отступы и комментарии для функций
Функции отделены друг от друга минимум одной пустой строкой. Для каждой функции необходимо краткое описание того, что она делает:
# Получить имя домена по его id
sub get_domain_name {
…
}
или так,
=item B<get_domain_name>($id)
Получить имя домена по его id
=cut
sub get_domain_name {
…
}
6. Приём входных параметров функций
Параметры принимаются с использованием конструкции:
my ($param1, $param2) = @_;
Она должна располагаться в первой строке функции и отделяться пустой строкой от последующего кода. Этот вариант считается стандартным и должен применяться всегда, кроме описанных ниже исключений.
Возможно использование shift и pop в сложных случаях, где это обоснованно (т. е. требуется изменение @_, либо используется хитрая последовательность параметров): некоторые случаи использования AUTOLOAD, работы с коллбэками и т. п.
В случае переменного количества параметров, если количество и смысл последующих параметров может варьироваться в зависимости от значения предыдущих параметров, тоже допускается принимать эти первые по счёту параметры с помощью shift:
my $action = shift;
my ($name, $value) = @_ if $action eq 'new';
my ($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 = @_;
7. Документирование входных параметров функций
Если аргументы функции нетривиальны (их назначение и набор допустимых значений не очевидны из их названия и контекста), после описания функции добавляется строка пояснения по аргументам. Если какой-либо аргумент может принимать конечное дискретное множество значений — это множество также перечисляется в комментариях.
Если используются именованные параметры — все возможные параметры также перечисляются в комментариях, обязательные параметры обозначаются звёздочкой:
# %param: action*, domain_name*, comment
# action: new, renew, delete
8. Не более 3-х позиционных параметров у функций
Функция может принимать не более 2-х, максимум 3-х ПОЗИЦИОННЫХ аргументов. При большем количестве аргументов либо проводится рефакторинг с целью уменьшения количества входных параметров, либо используются именованные параметры:
my %param = @_;
Именованные параметры обязательно документируются (см. п. 7)
9. Проверка аргументов
В случае использования именованных параметров,
если есть как обязательные, так и необязательные параметры,
желательно проверять наличие обязательных параметров.
В случае их отсутствия — вызывать исключение с помощью
Carp::confess
(для получения stack backtrace) или
Carp::croak
.
В случае использования позиционных параметров проверка наличия и
корректности переданных аргументов также приветствуется.
10. Документирование выходных параметров функций
Если выходные параметры функции не очевидны / нетривиальны, особенно это касается возврата сложных структур данных, желательно их документировать (после описания входных параметров).
11. Возврат скаляра или списка, в зависимости от wantarray
Если функция возвращает список значений, но из возвращаемого списка часто может использовать только первое значение, желательно выдавать только первое значение или весь список в зависимости от контекста:
return wantarray ? (user_id, username) : user_id;