В этой статье мы подробно рассказываем о методах именования классов, функций и переменных, которые позволяют улучшить читаемость вашего кода.
Это перевод статьи A Useful Framework for Naming Your Classes, Functions, and Variables
Автор оригинала XOR
«В компьютерном программировании соглашение об именах — набор правил для выбора последовательности символов, которая будет использоваться для идентификаторов, которые обозначают переменные, типы, функции и другие объекты в исходном коде и документации», — «Википедия»
Придумывать названия сложно!
В этой статье мы сосредоточимся на методе именования (P)A/HC/LC для того, чтобы улучшить читаемость кода. Эти рекомендации можно применить к любому языку программирования, в статье для примеров кода используется JavaScript.
В этой практике используется следующий шаблон для именования функции:
префикс? (P) + действие (A) + высокоуровневый контекст (HC) + низкоуровневый контекст? (LC)
Префикс расширяет смысл функции.
- is
Описывает свойство или состояние текущего контекста (обычно — логическое значение).
const color = 'blue';
const isBlue = (color === 'blue'); // свойство
const isPresent = true; // состояние
if (isBlue && isPresent) {
console.log('Blue is present!');
}
- has
Указывает, имеет ли текущий контекст определенное значение или состояние (обычно — логическое значение).
/* Плохо */
const isProductsExist = (productsCount > 0);
const areProductsPresent = (productsCount > 0);
/* Хорошо */
const hasProducts = (productsCount > 0);
- should
Отражает положительный условный оператор (обычно — логическое значение), связанный с определенным действием.
const shouldUpdateUrl = (url, expectedUrl) => url !== expectedUrl;
Читайте также: Цикл статей «Совершенный код. Ошибки именования в программировании» от Кирилла Мокевнина
Действие — это глагольная часть имени функции. Это самая важная часть в описании того, что делает функция.
- get
Получает доступ к данным немедленно (сокращение от getter для внутренних данных).
function getFruitsCount() {
return this.fruits.length;
}
- set
Безусловно присваивает переменной со значением A значение B.
let fruits = 0;
const setFruits = (nextFruits) => {
fruits = nextFruits;
};
setFruits(5);
console.log(fruits); // 5
- reset
Возвращает переменную к её начальному значению или состоянию.
const initialFruits = 5;
let fruits = initialFruits;
setFruits(10);
console.log(fruits); // 10
const resetFruits = () => {
fruits = initialFruits;
};
resetFruits();
console.log(fruits); // 5
- fetch
Выполняет запрос данных, для которого требуется время (например, асинхронный запрос).
const fetchPosts = (postCount) => fetch('https://api.dev/posts', {...});
- remove
Удаляет что-то откуда-то.
Например, если у вас есть коллекция выбранных фильтров на странице поиска, удаление одного из них из коллекции — это removeFilter
, а не deleteFilter
(именно так вы и скажете на английском языке):
const removeFilter = (filterName, filters) => filters.filter((name) => name !== filterName);
const selectedFilters = ['price', 'availability', 'size'];
removeFilter('price', selectedFilters);
- delete
Полностью стирает что-то. После операции сущность перестаёт существовать.
Представьте, что вы редактор контента, и есть пост, от которого вы хотите избавиться. Как только вы нажали на кнопку delete-post, CMS выполнила действие deletePost
, а не removePost
.
const deletePost = (id) => database.find({ id }).delete();
- compose
Создает новые данные из существующих. Обычно это применимо к строкам, объектам или функциям.
const composePageUrl = (pageName, pageId) => `${pageName.toLowerCase()}-${pageId}`;
- handle
Обработка действия. Часто используется при именовании обратного вызова.
const handleLinkClick = () => {
console.log('Clicked a link!');
};
link.addEventListener('click', handleLinkClick);
Контекст — это область, с которой работает функция.
Функция — это часто действие с чем-то. Важно указать, какова её рабочая область или, по крайней мере, ожидаемый тип данных.
/* Чистая функция, работающая с примитивами */
const filter = (list, predicate) => list.filter(predicate);
/* Функция, работающая непосредственно с сообщениями */
const getRecentPosts = (posts) => filter(posts, (post) => post.date === Date.now());
/*
Некоторые специфические для языка допущения позволяют опустить контекст.
Например, в JavaScript фильтр обычно работает с массивом (Array).
Добавление явного filterArray будет избыточным.
*/
В этом разделе мы предложим некоторые правила именования переменных, которые улучшат читаемость кода.
Имя должно быть коротким (Short), интуитивно понятным (Intuitive) и описательным (Descriptive).
/* Плохо */
const a = 5; // "a" может обозначать что угодно
const isPaginatable = (postsCount > 10); // "Paginatable" звучит крайне неестественно
const shouldPaginatize = (postsCount > 10); // Придуманные глаголы - это так весело!
/* Хорошо */
const postsCount = 5;
const hasPagination = (postsCount > 10);
const shouldDisplayPagination = (postsCount > 10); // альтернатива
Не используйте сокращения. Обычно они только ухудшают читаемость кода. Найти короткое, описательное имя может быть сложно, но сокращения не могут быть оправданием для того, чтобы этого не делать. Например:
/* Плохо */
const onItmClk = () => {};
/* Хорошо */
const onItemClick = () => {};
Всегда удаляйте контекст из имени, если это не снижает его читабельность.
class MenuItem {
/* Имя метода дублирует контекст (которым является "MenuItem") */
handleMenuItemClick(event) {
...
}
/* Читается как `MenuItem.handleClick()` */
handleClick(event) {
...
}
}
/* Плохо */
const isEnabled = (itemsCount > 3);
/* Хорошо */
const isDisabled = (itemsCount <= 3);
Как и префикс, имена переменных могут быть единственного или множественного числа в зависимости от того, имеют ли они одно значение или несколько.
/* Плохо */
const friends = 'Bob';
const friend = ['Bob', 'Tony', 'Tanya'];
/* Хорошо */
const friend = 'Bob';
const friends = ['Bob', 'Tony', 'Tanya'];
/* Просто ужасно */
const yyyymmdstr = moment().format("YYYY/MM/DD");
/* Гораздо лучше */
const currentDate = moment().format("YYYY/MM/DD");
Читайте также: Сложные простые задачи по программированию