Перевод статьи 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
Отражает положительный условный оператор (обычно логическое значение), связанный с определенным действием.
function shouldUpdateUrl(url, expectedUrl) {
return (url !== expectedUrl)
}
Действия - это глагольная часть имени функции. Это самая важная часть в описании того, что делает функция.
- get
Получает доступ к данным немедленно (т.е. сокращение от getter для внутренних данных).
function getFruitsCount() {
return this.fruits.length;
}
- set
Устанавливает переменную со значением A
в значение B
.
const fruits = 0
function setFruits(nextFruits) {
fruits = nextFruits
}
setFruits(5)
console.log(fruits) // 5
- reset
Возвращает переменную к ее начальному значению или состоянию.
const initialFruits = 5
const fruits = initialFruits
setFruits(10)
console.log(fruits) // 10
function resetFruits() {
fruits = initialFruits
}
resetFruits()
console.log(fruits) // 5
- fetch
Запрос данных, который требует время на исполнение (например, асинхронный запрос).
function fetchPosts(postCount) {
return fetch('https://api.dev/posts', {...})
}
- remove
Удаляет что-то откуда-то.
Например, если у вас есть коллекция выбранных фильтров на странице поиска, удаление одного из них из коллекции - это removeFilter
, а не deleteFilter
(и это то, как вы естественно скажете это на английском языке):
function removeFilter(filterName, filters) {
return filters.filter(name => name !== filterName)
}
const selectedFilters = ['price', 'availability', 'size']
removeFilter('price', selectedFilters)
- delete
Полностью стирает что-то из сферы бытия.
Представьте, что вы редактор контента, и есть тот пресловутый пост, от которого вы хотите избавиться. Как только вы нажали на блестящую кнопку delete-post, CMS выполнила действие deletePost
, а не removePost
.
function deletePost(id) {
return database.find({ id }).delete()
}
- compose
Создает новые данные из существующих. В основном это применимо к строкам, объектам или функциям.
function composePageUrl(pageName, pageId) {
return `${pageName.toLowerCase()}-${pageId}`
}
- handle
Обработка действия. Часто используется при именовании обратного вызова.
function handleLinkClick() {
console.log('Clicked a link!')
}
link.addEventListener('click', handleLinkClick)
Контекст - это область, с которой работает функция.
Функция - это часто действие с чем-то. Важно указать, какова ее рабочая область - или, по крайней мере, ожидаемый тип данных.
/* Чистая функция, работающая с примитивами */
function filter(predicate, list) {
return list.filter(predicate)
}
/* Функция, работающая непосредственно с сообщениями */
function getRecentPosts(posts) {
return filter(posts, (post) => post.date === Date.now())
}
/*
Некоторые специфические для языка допущения могут позволить опустить контекст.
Например, в JavaScript обычно фильтр работает с массивом (Array).
Добавление явного filterArray будет лишним.
*/
Имя функции | Префикс (P) | Действие (A) | Высокий контекст (HC) | Низкий контекст (LC) |
---|---|---|---|---|
getUser |
get |
User |
||
getUserMessages |
get |
User |
Messages |
|
handleClickOutside |
handle |
Click |
Outside |
|
shouldDisplayMessage |
should |
Display |
Message |
В этом разделе мы попытались сосредоточиться на некоторых правилах именования переменных, которые улучшат читаемость кода.
Имя должно быть коротким (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)
return <Button disabled={!isEnabled} />
/* Хорошо */
const isDisabled = (itemsCount <= 3)
return <Button disabled={isDisabled} />
Как и префикс, имена переменных могут быть единственного или множественного числа в зависимости от того, имеют ли они одно значение или несколько.
/* Плохо */
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");