Skip to content

Instantly share code, notes, and snippets.

@AABur
Last active October 23, 2022 13:33
Show Gist options
  • Save AABur/91501c2645fe51e613b7b4542d201d71 to your computer and use it in GitHub Desktop.
Save AABur/91501c2645fe51e613b7b4542d201d71 to your computer and use it in GitHub Desktop.

Практичная структура для именования классов, функций и переменных

Перевод статьи A Useful Framework for Naming Your Classes, Functions, and Variables

Автор оригинала XOR

"В компьютерном программировании соглашение об именах — набор правил для выбора последовательности символов, которая будет использоваться для идентификаторов, которые обозначают переменные, типы, функции и другие объекты в исходном коде и документации." - Википедия

Придумывать названия сложно!

В этой статье мы постараемся сосредоточиться на методе именования (P)A/HC/LC, надеясь, что это улучшит читаемость кода.

Хотя эти предложения можно применить к любому языку программирования, мы будем использовать JavaScript, чтобы проиллюстрировать их на практике.

Что значит (P)A/HC/LC?

Данная практика предлагает использовать следующий шаблон для именования функции.

префикс? (P) + действие (A) + высокоуровневый контекст (HC) + низкоуровневый контекст? (LC)

Что обозначает Префикс (P)?

Префикс расширяет смысл функции.

- 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

Пять принципов присвоения имени переменным

В этом разделе мы попытались сосредоточиться на некоторых правилах именования переменных, которые улучшат читаемость кода.

1. Следуйте S-I-D

Имя должно быть коротким (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) // альтернатива

2. Избегайте сокращений

Не используйте сокращения. Они не приносят ничего, кроме ухудшения читабельности кода. Найти короткое, описательное имя может быть сложно, но сокращения не могут быть оправданием для того, чтобы этого не делать. Например

    /* Плохо */
    const onItmClk = () => {}

    /* Хорошо */
    const onItemClick = () => {}

3. Избегайте дублирования контекста

Всегда удаляйте контекст из имени, если это не снижает его читабельность.

    class MenuItem {
    /* Имя метода дублирует контекст (которым является "MenuItem") */
    handleMenuItemClick = (event) => { ... }

    /* Читается как `MenuItem.handleClick()` */
    handleClick = (event) => { ... }

    }

4. Должно отражать ожидаемый результат

    /* Плохо */
    const isEnabled = (itemsCount > 3)
    return <Button disabled={!isEnabled} />

    /* Хорошо */
    const isDisabled = (itemsCount <= 3)
    return <Button disabled={isDisabled} />

5. Учитывайте единственное/множественное число

Как и префикс, имена переменных могут быть единственного или множественного числа в зависимости от того, имеют ли они одно значение или несколько.

    /* Плохо */
    const friends = 'Bob';
    const friend = ['Bob', 'Tony', 'Tanya'];

    /* Хорошо */
    const friend = 'Bob';
    const friends = ['Bob', 'Tony', 'Tanya'];

6. Используйте осмысленные и произносимые имена переменных

    const yyyymmdstr = moment().format("YYYY/MM/DD"); // просто ужасно

    // Вместо этого

    const currentDate = moment().format("YYYY/MM/DD");
05-29 15:57 ward._collect INFO Start get_info_for_modules
05-29 15:57 ward._collect INFO Handle case where path points directly to modules
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Next step0
05-29 15:57 ward._collect INFO Check for modules at the root of the specified path (or paths)
05-29 15:57 ward._collect INFO Now check for modules in every subdirectory
05-29 15:57 ward._collect INFO Next step1
05-29 15:57 ward._collect INFO Next step3
05-29 15:57 ward._collect INFO if we have seen this path before, skip it
05-29 15:57 ward._collect INFO Next step1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment