Перевод статьи «Clean up your code by applying these 7 rules».
В этой короткой статье я пройдусь по некоторым правилам, которые могут помочь вам улучшить ваш код. Все примеры написаны на JavaScript.
Я считаю, что читаемый код — это поддерживаемый код.
Моя цель как разработчика — писать высококачественный код. Он должен быть таким, чтобы любой разработчик в команде, какими бы навыками он ни обладал, мог его прочесть и, прочитав, понять.
Удаляйте ненужные комментарии
Конечно, бывает, что код очень сложный. Я это знаю и сам видел много примеров подобного. В таких случаях полезны и комментарии, и хорошо составленная документация.
Не поймите меня неверно. Я не поклонник комментариев в коде или Jsdoc в JavaScript. Конечно, за исключением случаев, когда они пригодились бы мне самому:)
Просто для того чтобы понять, что эта функция берет Х массивов и сливает их вместе в новый массив, мне не нужны комментарии.
function mergeArrays(...arrays) { let mergedArray = [] arrays.forEach(array => { mergedArray = [...mergedArray, ...array] }) return mergedArray }
Добавление Jsdoc к этому коду не улучшает его читаемость. Я ожидаю, что мои товарищи по команде знакомы с оператором расширения. Но если нет, им стоит спросить об этом на код-ревью.
И давайте не забывать в коде закомментированные блоки. Для этого есть одно-единственное решение: этот код нужно удалять. В Git есть прекрасная функция для просмотра старого кода, так зачем хранить его в закомментированном виде?
Пожалуйста, перестаньте превращать вашу кодовую базу в свалку.
Фокус на нейминге
Если вы посмотрите на имя mergeArrays, вам, по идее, должно быть совершенно очевидно, что эта функция комбинирует Х массивов и делает из них один массив.
Я знаю, что нейминг это непросто. И чем сложнее функция, тем тяжелее придумать для нее подходящее имя. Для облегчения этой задачи я пользуюсь одним правилом.
Представьте функцию, которая объединяет два массива чисел и генерирует из этих чисел новый уникальный список. Как ее назвать? Как-нибудь так?
function mergeNumberListIntoUniqueList(listOne, listTwo) { return [...new Set([...listOne, ...listTwo])] }
Это имя не плохое, ведь оно точно отражает суть этой функции. Проблема в том, что функция выполняет две задачи. А чем больше задач выполняет функция, тем труднее подобрать для нее имя. Если разделить эту функцию на две разные, каждую из них будет куда легче назвать. А кроме того, код станет более пригодным для повторного использования.
function mergeLists(listOne, listTwo) { return [...listOne, ...listTwo] } function createUniqueList(list) { return [...new Set(list)] }
Конечно, программисту проще создать красивый однострочник без вызовов дополнительной функции. Но порой однострочники просто хуже читаются.
If-предложения
Я не смог подобрать более подходящий заголовок для этой проблемы. Видите, нейминг — это сложно!
Подобный код мне приходилось видеть довольно часто.
Проблема
if(value === 'duck' || value === 'dog' || value === 'cat') { // ... }
Решение
const options = ['duck', 'dog', 'cat']; if (options.includes(value)) { // ... }
Делая так, вы создаете читаемый отрывок кода, который выглядит, как обычное предложение на английском языке.
Но если варианты включают значения, тогда…
Ранний выход
Этот принцип называется по-разному, но я выбрал «ранний выход».
Я покажу вам отрывок кода. Уверен, вам случалось видеть нечто подобное.
function handleEvent(event) { if (event) { const target = event.target; if (target) { // Your awesome piece of code that uses target } } }
Здесь мы пытаемся проверить, не ложь ли объект event и доступно ли свойство target. Проблема в том, что мы используем целых два if-оборота.
Давайте посмотрим, как здесь можно сделать «ранний выход».
function handleEvent(event) { if (!event || !event.target) { return; } // Your awesome piece of code that uses target }
Применяя правило раннего выхода, вы проверяете, не ложь ли event и event.target. Нам сразу становится ясно, что event.target — не ложь. Кроме того, если это утверждение все-таки будет ложным, никакой другой код не будет выполняться.
Деструктуризация
В JavaScript возможна деструктуризация объектов и массивов. Согласно документации, найденной на developer.mozilla.org, «Синтаксис деструктурирующего присваивания в выражениях JavaScript позволяет извлекать данные из массивов или объектов при помощи синтаксиса, подобного объявлению массива или литералов в объекте».
Примеры кода:
// Destructuring an object const numbers = {one: 1, two: 2}; const {one, two} = numbers; console.log(one); // 1 console.log(two); // 2 // Destructuring an array const numbers = [1, 2, 3, 4, 5]; const [one, two] = numbers; console.log(one); // 1 console.log(two); // 2
Проблема деструктуризации в том, что иногда для свойства создается плохое имя. Прекрасный пример — извлечение данных из API и получение объекта response, имеющего свойство data.
const url = "http://localhost:8080/api/v1/organizers/1" const response = await axios.get(url) const {name} = response.data
Этот пример кода показывает, что вы извлекаете organizer с id 1. Объект organizer имеет имя. Вы его деструктуризируете. Ничего плохого в этом нет.
Этот код работает, и это прекрасно. Но почему имя по-прежнему name? Будет ли повсеместно только свойство name? Опять же, из какого объекта это name?
Старайтесь избегать подобных вопросов путем переименования свойства.
const url = "http://localhost:8080/api/v1/organizers/1" const response = await axios.get(url) const {name: organizerName} = response.data
Теперь код стал более читаемым. Каждый поймет, что переменная — это имя organizer-а.
Правило бойскаута
Вам случалось слышать правило «Оставь все после себя в лучшем виде, чем было до тебя»? Это и есть правило бойскаута. Оставляйте код в лучшем виде, чем он был, когда вы его нашли. Вы обнаружили запах кода? Проведите рефакторинг! Нашли неиспольуземую переменную? Удалите ее!
Я люблю сравнивать это с уборкой в доме. Представьте, что каждый член семьи оставляет грязные тарелки в раковине, складирует мусор в коридоре, а грязное белье в ванной. Каждое воскресенье вам приходится убирать весь дом, а это занимает больше четырех часов. Вам это нравится?
Уверен, что нет. Так вот, если каждый сразу будет понемножку убирать в доме, то в воскресенье работы будет гораздо меньше.
То же самое касается кода. Если каждый запах кода остается в кодовой базе, если никто не убирает неиспользуемые переменные, то линтер будет сходить с ума и выбрасывать по 77 предупреждений. Вам придется разгребать завалы. Но если каждый будет подходить к делу ответственно и применять правило бойскаута, это решит многие проблемы.
Стиль кода
Наконец, определите какой-то единый стиль кода в вашей команде. Совершенно все равно, нравятся вам одинарные или двойные кавычки, пробелы или табы, наличие или отсутствие замыкающих запятых. Выберите что-то одно и придерживайтесь этого выбора. Из инструментов вам могут в этом помочь линтеры и/или Prettier.
Вообще есть много инструментов для решения подобного рода проблем. Мой любимый — pre-commit hook с использованием Husky. В документации Prettier тоже есть страница о pre-commit hook-ах.
Этот pre-commit hook запускает заранее настроенную команду перед каждый коммитом. Если вы настроите все правильно, будет запускаться Prettier, и во всех файлах принудительным образом применятся все прописанные правила. Таким образом весь ваш код гарантированно будет написан в одном стиле.
Итоги
Я знаю, что одни правила очевидны, а другие — не слишком. Но я как профессиональный разработчик работал со многими кодовыми базами. Могу сказать, что чем крупнее кодовая база, тем лучше видна важность соблюдения всех этих правил. Но это не означает, что в маленьких проектах можно всем этим пренебречь. Улучшение качества вашего кода позволит вам стать более эффективным разработчиком, даже если вы работаете над чем-то небольшим.
Помимо всего прочего, благодаря соблюдению вами этих правил вашим товарищам по команде будет легче читать ваш код и они станут чаще одобрять ваши пул-реквесты. Как я уже говорил, читаемый код — это более поддерживаемый код, но кроме этого есть и другие преимущества.
Если хотите узнать больше об этом, почитайте книгу «Чистый код» Роберта Мартина.
[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]