Введение

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

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

Использование описательных имен - одно из самых простых изменений, которые вы можете внести в свой рабочий процесс. Используя описательные имена для функций и переменных, ваш код может стать почти полностью самодокументированным, хотя я все же предлагаю добавлять комментарии к сложным функциям. Мы все там были: вы открываете старый проект или проект, унаследованный от другого разработчика, и он полон общих имен, которые ничего не значат. Рассмотрим следующий пример: код извлекает некоторый items, из которого он создает новый массив, Alt items, прежде чем установить для свойства icon значение «звездочка». В этом случае вы, как разработчик, не имеете ни малейшего представления о том, какие items извлекаются и обрабатываются:

let items = fetchItems()
let altItems = items.filter(item => item.featured == true)
altItems.forEach(item => {
   item.icon = 'star'
})

Вы можете легко сделать этот фрагмент кода более понятным с помощью описательных имен. Для аргументов предположим, что ваша функция выборки возвращает array из articles. Теперь посмотрите на следующий пример того, как вы можете переписать предыдущий фрагмент кода с более информативными именами:

let articles = fetchArticles()
let featuredArticles = articles.filter(article => article.featured == true)
featuredArticles.forEach(featuredArticle => {
   featuredArticle.icon = 'star'
})

Извлечь общие функции

При написании на любом языке программирования нередки повторяющиеся задачи в рамках функций и циклов. Конечно, вы можете повторяться каждый раз, однако ваш код скоро станет трудно поддерживать. В следующем примере есть 2 цикла, один для articles и один для projects, для каждого article / project код добавит стандартизированную отформатированную дату:

articles.forEach(article => {
    let date = new Date(article.createdAt),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()
    article.formattedDate = `${day}/${month}/{year}`
})
projects.forEach(project => {
    let date = new Date(project.createdAt),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()
    project.formattedDate = `${day}/${month}/{year}`
})

Представьте, что теперь вы хотите изменить формат даты, теперь у вас есть 2 места, где вам нужно обновить форматирование: цикл articles и цикл projects. Однако, извлекая функциональность даты из каждого цикла и создав новую функцию, вы можете повторно использовать один и тот же код в каждом из них. Затем, если вы захотите изменить формат даты, вам нужно будет сделать это только в одном месте, даже если у вас есть сотни экземпляров. Теперь посмотрите на следующий пример того, как вы можете выбрать рефакторинг предыдущего фрагмента и извлечь функцию форматирования даты.

const formatDate = (rawDate) => {
    let date = new Date(rawDate),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()
    return `${day}/${month}/{year}`
}
articles.forEach(article => {
    article.formattedDate = formatDate(article.createdAt)
})
projects.forEach(project => {
    project.formattedDate = formatDate(project.createdAt)
})

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

const formatDate = (rawDate) => {
    let date = new Date(rawDate)
    return `${date.getDate()}/${date.getMonth()+1}/{date.getFullYear()}`
}

Избегайте вложенных условных операторов и возвращайтесь раньше

Условные утверждения являются обычным явлением почти в каждом веб-приложении, они определяют, является ли утверждение истинным или ложным, и возвращают или устанавливают соответствующие данные. Проблема с условными предложениями в том, что они могут очень быстро стать неприглядными и нечитаемыми. Рассмотрим следующий пример. Функция getShopTradingStatement возвращает строку в зависимости от того, торгует ли магазин в данный момент, а если да, то был ли у магазина день открытия:

const getShopTradingStatement = (shop) => {
    if (shop.isTrading) {
        if (shop.openFrom < Date.now()) {
            return `This shop is currently trading!`
        }
        else {
            return `This shop will open it's doors from ${shop.openFrom}`
        }
    }
    else {
       return `This shop is no longer trading.`
    }
}

Вложение утверждений таким образом, хотя и совершенно достоверно, уже кажется загроможденным. Изменив свои заявления и воспользовавшись преимуществами ранних возвратов, вы можете сделать ту же самую функциональность намного более аккуратной. Теперь посмотрите на следующий пример того, как вы можете выбрать рефакторинг предыдущего фрагмента, вернув выходные данные вашего основного оператора else на раннем этапе:

const getShopTradingStatement = (shop) => {
    if (!shop.isTrading) return `This shop is no longer trading.`
    if (shop.openFrom < Date.now()) return `This shop is currently trading!`
    return `This shop will open it's doors from ${shop.openFrom}`
}

Используйте таблицы поиска

Таблицы поиска - отличный способ избавиться от беспорядочных, повторяющихся if операторов. В следующем примере у вас есть userHasAccessPermissionsForTask функция, которая принимает роль пользователей и задачу, которую они хотят выполнить. Функция проверяет 3 возможные роли пользователей и соответствующие разрешения для каждой из них. Если у роли пользователя есть разрешения на выполнение задачи, функция вернет true, иначе она вернет false:

const userHasAccessPermissionsForTask = (userRole, task) => {
    if (userRole == 'admin' && ['write', 'edit', 'read'].includes(task)) {
        return true
    }
    if (userRole == 'editor' && ['edit', 'read'].includes(task)) {
        return true
    }
    if (userRole == 'subscriber' && ['read'].includes(task)) {
        return true
    }
    return false
}

Предыдущий фрагмент кода вполне допустим, но не особенно ясен. Вы также повторяете свою includes функцию для каждого if оператора. Если в будущем вы захотите проверить эти данные другим способом, вам нужно будет убедиться, что вы выполнили это в трех местах. Вы могли бы привести аргумент в пользу извлечения этой функции как ее собственной функции, но создание функции, возвращающей встроенную функцию, кажется немного странным, не так ли? К счастью, с помощью справочных таблиц всего этого можно избежать. Теперь посмотрите на следующий пример того, как вы можете выбрать рефакторинг предыдущего фрагмента с помощью таблицы поиска. Таблица поиска - это объект, который в данном случае использует роли пользователей в качестве ключей и разрешения в качестве значений. Теперь вы можете вернуть одну функцию includes, которая ссылается на свойство объекта permissions с ключом, равным заданному userRole:

const userHasAccessPermissionsForTask = (userRole, task) => {
    const permissions = {
        admin: ['write', 'edit', 'read'],
        editor: ['edit', 'read'],
        subscriber: ['read']
    }
    return permissions[userRole].includes(task)
}

Начните делиться своим кодом

Я думаю, что совместное использование вашего кода, возможно, одна из самых ценных вещей, которые вы можете сделать, если хотите продолжать расти и учиться как разработчик. В технологиях все быстро меняется, и очень легко остаться позади, особенно когда вы заняты. Совместное использование вашего кода, будь то через обзоры кода, парное программирование *, даже через ведение блога и социальные сети, такие как Twitter, позволяет людям подвергать сомнению ваш подход. Поначалу это может показаться пугающим, но вопрос о вашем подходе не означает, что вы ошибаетесь, но это позволяет вам открыть свой разум для новых и / или различных способов решения проблем в будущем. В свою очередь, ваши ответы могут помочь тем, кто задает вам вопросы, в их будущих проектах.

* Если вы хотите объединить программы в пары, сохраняя при этом социальное дистанцирование или работая удаленно, вы можете попробовать программное обеспечение для парного программирования, такое как Tuple или расширение VS code Liveshare.

Вывод

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

Если вы нашли эту статью полезной, подпишитесь на меня на Medium, Dev.to и / или Twitter.