Любой код не является хаотичным набором знаков, а производит вполне конкретные операции над вполне конкретными величинами, у которых есть естественный человеческий смысл и соответствующие названия.
И смысл, и названия происходят из предметной области, с которой работает программист, даже если эта предметная область не находится в физическом или воображаемом мире.
При написании кода автор превращает элементы предметной области и действия над ними в конструкции языка программирования, при чтении же кода он сам или другой программист выполняет обратное превращение — из конструкций языка в элементы предметной области и то, что с ними происходит.
Называние переменных в точном соответствии с названиями элементов предметной области, которые они выражают, а функций и методов — в соответствии с действиями над элементами предметной области позволяет производить это обратное превращение гораздо быстрее.
Всегда спрашивай себя: «Что здесь происходит с точки зрения предметной области?», «Как это называется на человеческом языке?».
Таким способом достигается достигается эффект, описанный Робертом Мартином: «код должен читаться как хорошая проза».
Как давать названия функциям
Мартин Фаулер в своём посте FunctionLength (на который я очень люблю ссылаться) даёт хорошее представление о том, исходя из чего следует выбирать название.
Мартин показывает два аспекта функций:
- намерение: какого результата достигает функция, какова цель её существования;
- реализация: каким образом достигается результат, при помощи каких преобразований.
Эти аспекты необходимо разделять по очень простой причине: один и тот же результат может быть достигнут множеством разных способов.
В сущности, работа программиста как раз и состоит в том, чтобы придумывать возможные способы достижения заданной цели (алгоритмы) и выбирать из них оптимальный (впрочем, этим же самым занимаются представители многих других профессий, например, водители).
Так вот, название функции должно называть намерение, а не реализацию.
Команды и запросы
Согласно рекомендации Роберта Мартина, функция должна либо делать что-то, либо отвечать на какой-то вопрос (запрос), то есть возвращать результат.
Соответственно, название функции должно называть действие или вопрос/запрос.
Называние функции-команды
Функция-команда должна называться в соответствии с тем конечным результатом, которого она достигает, никак не обозначая при этом конкретных шагов, которые для достижения этого результата будут сделаны. Как правило, функция-команда что-то где-то меняет (поля в объекте и/или в таблице БД, создаёт новые объекты и записи в БД, отправляет сообщения и т. п.).
Причём помним, что названия должны выбираться исходя из названий сущности предметной области, в которой «работает» функция.
Название функций-команд принято начинать с глагола, чтобы подчеркнуть их директивный характер.
Пример: команда отмены заказа в интернет-магазине.
$order = Order::find($order_id);
$order->cancel($reason);
public function cancel($reason) {
$this->status = 'cancelled';
$this->cancellation_reason = $reason;
$this->save();
}
В простейшем примере отмена заказа может выглядеть просто как присвоение статуса заказа и сохранение сделанного изменения в БД.
В реальности же при отмене заказа требуется произвести массу операций:
- проверить возможность отмены заказа;
- вернуть деньги покупателю;
- оповестить отдел сборки о необходимости возврата товаров на склад;
- создать записи о приходе товаров на склад в результате отмены заказа;
- создать запись в истории статусов заказа;
- оповестить пользователя о результате операции, и т. д.
Естественно, мы не должны отражать все эти шаги в названии функции, мы говорим лишь о том, что функция должна попытаться сделать, каков будет результат её выполнения (отмена заказа).
Называние функций-запросов (вопросов)
Функции-запросы ничего не меняют, а только возвращают информацию тому, кто её запросил.
Это может быть транспортировка информации (запрос), результат переработки одних данных в другие (тоже запрос), переработка где-то плюс транспортировка к нам (опять запрос), либо информация о состоянии дел (вопрос).
Иногда название функций-запросов начинается со слова «get» (но мне больше нравится без него). В названиях функций, связанных с транспортировкой, используются глаголы. Названия функций-вопросов принято начинать с глаголов «is» или «has».
В любом случае название должно содержать существительные и прилагательные, описывающие получаемую от функции информацию, опять же, без называния способа, которым функция эту информацию производит. То есть название даётся с точки зрения пользователя функции, а не с точки зрения самой функции. Мы как бы смотрим на функцию извне и видим только её результат (режим «чёрного ящика»), а не внутреннее устройство функции.
Пример
public function concatenated_names() {
return$this->first_name . ' ' . $this->last_name;
}
concatenated_names
называет операцию, которая внутри метода производится со строками (то есть называет реализацию), а поэтому неудачное. Правильное название метода — full_name
, оно отражает результат выполнения функции.
Литература
- Фаулер М. Рефакторинг: улучшение существующего кода. — СПб: Символ-Плюс, 2016.