Ответы на все вопросы о том, что, почему, когда и как насчет статического анализа кода в JavaScript

Вы страдаете от плохо написанного кода? Ваша кодовая база пронизана несоответствиями? Испытываете ли вы беспокойство каждый раз, когда проверяете ваш код? Если вы ответили «да» на любой из этих вопросов, вам может помочь статический анализ кода.

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

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

Что такое статический анализ кода?

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

Чем это отличается от тестирования?

Вы можете подумать: «Если я напишу подробные тесты всех своих модулей и функциональных тестов на системном уровне, и все они пройдут, мой код будет без ошибок, верно?» Да, это так. Поздравляю. Но код без ошибок - это не то же самое, что хороший код; это еще не все. Это та область, где сияет статический анализ.

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

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

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

Зачем использовать статический анализ кода?

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

Углубленное сканирование кода

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

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

Люди делают ошибки. Только 15% кодовых баз, которые устанавливают JSHint, популярный инструмент проверки кода для JavaScript, проходят без проблем. Это просто показывает, насколько жизненно важно, чтобы некоторые компьютерные глаза также проверяли ваш код.

Пример:

Рассмотрим эту программу, позволяющую пользователю собирать свои любимые фрукты. Если вы не выбрали вариант, по умолчанию будет использоваться «Манго».

let fruits = ['Apple', 'Banana', 'Cherry', 'Mango']
function getFruit(index) {
	index = index || 3 // Everybody likes mangoes
	return fruits[index]
}

Этот код работает. То есть для всех входов, кроме 0. Если вы не будете очень тщательными, ваши тесты также пройдут без единой задержки.

getFruit()  // Mango
getFruit(2) // Cherry
getFruit(0) // Mango (expected Apple!)

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

let fruits = ['Apple', 'Banana', 'Cherry', 'Mango']
function getFruit(index) {
	index = index ?? 3 // Everybody likes mangoes
	return fruits[index]
}

Поручни и тренировочные колеса

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

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

Для каждого языка, на котором я когда-либо работал, написан линтер. В JavaScript есть ESLint; У Python есть черный, а у Ruby есть RuboCop. Эти линтеры выполняют простую работу по проверке соответствия вашего кода установленному набору стилевых правил. Некоторые линтеры, такие как RuboCop, также применяют передовые методы, такие как атомарные функции и улучшенные имена переменных. Такие подсказки очень часто помогают при обнаружении и исправлении ошибок до того, как они вызовут проблемы в производственной среде.

Пример:

Рассмотрим следующий фрагмент кода JavaScript, в котором вы печатаете название фрукта из списка. Список остается неизменным на протяжении всей программы.

var fruits = ['Apple', 'Banana', 'Cherry', 'Mango']
console.log(fruits[0])

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

const fruits = ['Apple', 'Banana', 'Cherry', 'Mango']
console.log(fruits[0])

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

Мгновенно обнаруживайте проблемы…

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

Статические анализаторы кода не страдают от этой проблемы. Вам не нужно писать тесты; вы можете импортировать целые библиотеки пресетов. Кроме того, статические анализаторы работают невероятно быстро, поскольку не требует выполнения кода! Фактически, многие линтеры интегрируются с редактором и выделяют проблемы с кодом в режиме реального времени по мере ввода.

Пример:

Иногда в реальном времени просто слишком быстро.

… Исправьте их так же быстро

Большинство статических анализаторов, особенно линтеров и форматеров, не только укажут на проблемы, но и могут исправить большинство из них. Линтеры типа Black for Python и ESLint for JavaScript интегрируются с IDE и могут автоматически исправлять отредактированные файлы, как только вы их сохраняете.

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

Пример:

ESLint имеет флаг --fix, который устраняет общие проблемы, такие как ненужные точки с запятой, конечные пробелы и висячие запятые.

Рассмотрим тот же фрагмент кода из нескольких последних примеров. (Здесь · обозначает пробел.)

var fruits = [
	'Apple',
  'Banana',
  'Cherry',··
	'Mango'
];

Запустите ESLint с флагом --fix, и через несколько секунд вы получите его.

const fruits = [
	'Apple',
	'Banana',
	'Cherry',
	'Mango',
]

Намного лучше!

Ведомость материалов

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

Когда вы создаете приложение, вы неизбежно используете фреймворки и инструменты, созданные другими разработчиками. В свою очередь, эти фреймворки используют фреймворки, созданные другими разработчиками. И прежде чем вы это узнаете, установка простого приложения Vue.js может поместить тысячи пакетов в ваш node_modules/ каталог.

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

Пример:

GitHub обеспечивает сканирование зависимостей с помощью Dependabot. npm также обеспечивает сканирование уязвимостей с помощью команды npm audit. И Dependabot, и npm audit предлагают возможность автоматического обновления уязвимых пакетов до их исправленных версий.

Автоматизируйте скучные вещи

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

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

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

Когда

Теперь. Да, это правильно. Я сказал прямо сейчас. Позднее, чем сейчас, уже слишком поздно. Вы бы достигли второго шага «Как», если бы мне не пришлось вас так сильно убеждать.

Как

Настроить очень просто. Поскольку мы неоднократно здесь говорили о ESLint, давайте просто настроим его в качестве примера проекта.

Сделать новый проект

Создайте новый каталог для вашего проекта. Войдите в каталог и инициализируйте пакет Node.js в каталоге. Мастер npm init задаст вам ряд вопросов. Когда вы закончите, у вас будет новый пакет Node.js для работы.

$ mkdir wuphf.com
$ cd wuphf.com
$ npm init

Установить ESLint

Установите ESLint. Это слишком просто.

$ npm install eslint

Настроить ESLint

Выполните следующую команду, чтобы вызвать мастер ESLint.

$ ./node_modules/.bin/eslint --init

Этот мастер задает множество вопросов о том, как вы будете использовать ESLint в проекте. Обязательно выберите набор правил Airbnb. Когда установка будет завершена, в каталоге будет файл .eslintrc.js.

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

module.exports = {
  env: {
    es2021: true,
    node: true,
  },
  extends: [
    'airbnb-base',
  ],
  parserOptions: {
    ecmaVersion: 12,
  },
  overrides: [
		{
      files: ['*.js'],
      rules: {
        'no-console': 'off',
      },
    },
	],
};

Зафиксируйте этот файл в системе контроля версий.

Вот и все! Все файлы JavaScript в проекте теперь будут постоянно сканироваться ESLint. Я также рекомендую установить Husky, чтобы запускать задание lint перед каждой фиксацией, чтобы вы никогда не проверяли плохой код в своей VCS.

Конец

Это все. Статически анализировать код действительно просто, а преимуществ так много, что нет причин не делать это.

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

Первоначально опубликовано в Блоге DeepSource.

Больше контента на plainenglish.io