Как писать чистый код: обзор лучших практик JavaScript

1
954
views

Перевод статьи «How to Write Clean Code: an Overview of JavaScript Best Practices and Coding Conventions».

Как писать чистый код

Соглашения о написании кода (англ. Coding conventions) это руководства по стилю в программировании. Обычно они затрагивают следующие темы:

  • Правила нейминга и объявления переменных и функций.
  • Правила использования пробелов, отступов и комментирования.
  • Принципы и практики программирования.

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

Соглашения о написании кода нацелены на поддержание качества кода, улучшение его читаемости и облегчение поддерживаемости. Эти соглашения могут иметь форму вполне конкретной документации, которой должна следовать команда, или быть просто вашим личным подходом к программированию.

«Чистый код читается, как хорошо написанная проза. Чистый код никогда не затемняет намерения проектировщика; он полон четких абстракций и простых линий передачи управления», – Грэди Буч.

Соглашения о написании кода

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

Магические числа

Это жестко прописанные числа, значение которых не ясно. Впервые взглянув на этот код, вы даже не представляете, что это за число такое — 86400.

for(let i = 0; i < 86400; i += 1) {
  // ...
}

Будет гораздо лучше, если вы отредактируете такой код, прописав константу:

const SECOND_IN_A_DAY = 86400;

for(let i = 0; i < SECOND_IN_A_DAY; i += 1) {
  // ...
}

Таким образом любой читатель будет знать, что речь идет о количестве секунд в сутках.

Глубокая вложенность

Если в вашем коде много вложенных циклов или условий, возможно, что-то следует вынести в отдельную функцию.

const exampleArray = [ [ [ 'value' ] ] ];

exampleArray.forEach((arr1) => {
  arr1.forEach((arr2) => {
    arr2.forEach((el) => {
      console.log(el)
    })
  })
})

// output: 'value'

В данном примере мы можем создать функцию, которая будет перебирать все массивы и возвращать итоговое значение:

const exampleArray = [ [ [ 'value' ] ] ];

const retrieveFinalValue = (element) => {
  if(Array.isArray(element)) {
    return fetchValue(element[0]);
  }

  return element;
}

// output: 'value'

Прекращайте писать комментарии

Чистый код и комментарии

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

«Несмотря на то что комментарии по сути не являются ни чем-то плохим, ни чем-то хорошим, они часто используются в качестве «костылей». Код надо писать так, будто комментарии вообще не существуют. Это будет заставлять вас писать как можно более простым и самодокументирующим способом», – Джефф Атвуд.

Код должен говорить сам за себя!

Избегайте крупных функций

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

const addMultiplySubtract = (a, b, c) => {
  const addition = a + b + c;
  const multiplication = a * b * c;
  const subtraction = a - b - c;

  return `${addition} ${multiplication} ${subtraction}`;
}

Будет лучше создать несколько разных функций, чтобы разделить логику:

const add = (a, b, c) => a + b + c;
const multiply = (a, b, c) => a * b * c;
const subtract = (a, b, c) => a - b - c;

Повторы кода

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

Хорошей иллюстрацией может послужить наш пример с глубокой вложенностью:

const exampleArray = [ [ [ 'value' ] ] ];

exampleArray.forEach((arr1) => {
  arr1.forEach((arr2) => {
    arr2.forEach((el) => {
      console.log(el)
    })
  })
})

Здесь у нас много повторяющегося кода. Будет гораздо лучше выделить его в отдельную функцию и управлять логикой иначе, с меньшим количеством повторов:

const exampleArray = [ [ [ 'value' ] ] ];

const retrieveFinalValue = (element) => {
  if(Array.isArray(element)) {
    return fetchValue(element[0]);
  }

  return element;
}

Другим хорошим примером повтора кода может послужить извлечение данных из параметров:

const getUserCredentials = (user) => {
  const name = user.name;
  const surname = user.surname;
  const password = user.password;
}

Используя деструктуризацию объекта (ES6), мы можем просто сделать следующее:

const getUserCredentials = (user) => {
  const { name, surname, password } = user;
}

Имена переменных

Camel case («верблюжий регистр») в JavaScript используется практически всегда. Это стандарт для написания имен переменных и функций.

Суть его в том, что в имени первое слово должно начинаться со строчной буквы (нижний регистр), а все первые буквы последующих слов должны быть заглавными (верхний регистр). Вот несколько примеров:

thisIsARandomCamelCaseName, camelCase, exampleFunctionName. 

В общем, вы уловили.

Использование осмысленных имен

getUserData и getUserInfo — довольно нечеткие имена. О каких данных и какой информации идет речь?

Важно, чтобы имена наших функций, методов и переменных выражали их точное значение.

GetUserPost — куда лучшее имя, поскольку здесь мы точно понимаем, что извлекаем.

В случае сомнений выбирайте описательность, а не краткость

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

findUserByNameOrEmail и setUserLoggedInTrue лучше, чем
findUser.

Если есть более короткий вариант, используйте его

Чистый код и краткость

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

Используйте подходящие по смыслу глаголы

Функции обычно создают, читают, обновляют или удаляют (create, read, update or delete) что-либо. Можно подойти к делу даже более тщательно, чтобы ваши функции создавали, извлекали, устанавливали, добавляли, убирали, сбрасывали и удаляли (create, get, set, add, remove, reset, delete) разные вещи.

Имя функции должно быть глаголом или фразой, содержащей глагол, и должно сообщать о том, что эта функция делает.

При этом следует быть последовательным. Т.е., для извлечения данных всегда использовать get, а не get, retrieve, return и десять тысяч других слов.

В общем, должно быть

getQuestions, getUserPosts, getUsers, 

а не

getQuestions, returnUsers, retrieveUsers.

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

Имена булевых переменных должны хорошо читаться в if-then предложениях

Есть хороший тест для имен булевых переменных. Подставьте такое имя в if-then предложение и прочтите вслух. Если читается, как нормальный текст, все в порядке.

Например, если вы проверяем характеристики машины, какой нейминг кажется вам более удобным:

sedan, sold, green, airbag

или

isSedan, isSold, isGreen, hasAirbag?

Если мы проверяем эти характеристики, мы можем сделать что-то вроде

car.isSedan, car.isSold, car.hasAirbag (последнее гораздо
лучше, чем car.airbags).

Таким образом читатель сразу сможет понять, что мы имеем дело с булевыми значениями.

Такие имена переменных звучат более естественно и облегчают чтение программы.

Используйте существительные для имен классов

Классы не принимают вещи, они и есть вещи. Более конкретно, они являются шаблонами чего-либо. Поэтому следует использовать

class Car = {…}

а не

class MakeCar {...}.

Если бы вы собирались создать машину, вы бы не говорили «создать новую СоздатьМашину», вы бы сказали «создать новую Машину».

Используйте PascalCase для имен классов

Благодаря Pascal case вы сможете с легкостью отличать, что в вашем коде является классом, а что нет.

class Task {…}

а не

class task {...}.

Константы пишите в верхнем регистре

Константы и чистый код

Помните, мы создавали константу с количеством секунд в сутках?

SECOND_IN_A_DAY = 86400

Значение константы это нечто неизменное. Это соглашение уходит корнями в С и не всегда соблюдается в JavaScript.

Имейте в виду, что const и constant (константа) это не одно и то же. Объявление const просто означает, что значение не изменяется путем повторного присваивания. В то время как значение истинной константы это примитивное значение, которое позже не будет меняться.

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

Таким образом,

const HOURS_IN_DAY = 24;

и

const USER_AGE = 30;

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

Избегайте однобуквенных имен переменных

В долгосрочной перспективе от слишком коротких имен больше хлопот, чем экономии на нажатиях клавиш.

Имена должны быть краткими и описательными. Переменная, инициализированная глобально, может в конечном итоге использоваться через сотню строк. Если она обозначается одной буквой, легко забыть, что это за переменная.

const dueDate = new Date()

гораздо лучше, чем

const d = new Date();

и

const query = () => { ... };

тоже гораздо лучше, чем

const q = () => { ... };

Однобуквенные имена можно использовать в маленьких функциях или в качестве индекса в цикле (это нормально):

for(let i = 0; i < 10>; i ++) {
  // ...
}

Заключение

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

Чистый код легко поддерживать в дальнейшем, он хорош для каждого отдельного разработчика и для команды в целом. И его намного легче читать.

Характеристики чистого кода:

  • «Он должен быть элегантным: чистый код приятно читать. Чтение этого кода должно вызывать у вас улыбку, как мастерски сделанная музыкальная шкатулка или красивая машина».
  • «Чистый код сфокусирован: каждая функция, класс, модуль служат какой-то конкретной цели и не загромождаются окружающими деталями».
  • «Чистый код это забота. Кто-то потратил время на то, чтобы сделать свой код простым и упорядоченным. Этот человек уделил должное внимание деталям. Он проявил заботу».

1 КОММЕНТАРИЙ

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here