Child pages
  • Функции
Skip to end of metadata
Go to start of metadata

Одна функция выполняет одну задачу

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

Имена функций должны содержать глагол

Наименования функций должны включать глагол, например «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;
  • No labels