Автор — Дэвид Хейни (David Haney), ведущий инженер-программист Stack Overflow
Итак, разработчики, время для серьёзного разговора. Вы уже наверное в курсе, что на этой неделе React, Babel и куча других популярных пакетов на NPM сломались. Причина довольно удивительная.
Простой пакет NPM под названием left-pad был установлен как зависимость в React, Babel и других пакетах. Модуль, который на момент написания этого поста, имеет 11 звёзд на Github (сейчас 323 — прим.пер). Весь пакет состоит из 11 простых строчек, которые реализуют примитивную функцию вставки пробелов в левой части строк. Если какие-то из ссылок когда-нибудь умрут, вот его код:
Узнав о бедствии, которое случилось из-за left-pad, я начал исследовать экосистему NPM. И вот что обнаружил, среди прочего:
Всё это заставляет задать вопрос…
В каком из параллельных миров вышеперечисленные решения являются наилучшими? Как сотни зависимостей и 28 000 файлов для пустого шаблона можно назвать чем-то ещё, кроме чрезмерной сложности и безумия?
Создаётся впечатление, что участники экосистемы NPM взрастили фетиш микропакетов. Вместо того, чтобы написать любую функцию или код, они как будто предпочитают установить зависимость на что-то написанное кем-то другим. Мне кажется, что вся работа программиста в экосистеме NPM сводится к написанию как можно меньшего количества кода, чтобы связать вместе существующие библиотеки, чтобы создать нечто новое, функционирующее уникальным образом для личных или коммерческих нужд.
Функции слишком малы, чтобы попасть в пакет и зависимость. У чистых функций нет связи; это случайные фрагменты кода и ничего больше. Кому нужна зависимость от косинуса? Вместо этого нам бы по-настоящему понравилась зависимость от пакета «тригонометрия», который охватывает много хитрых функций, которые мы не хотим писать сами. Это гораздо больше похоже на то, как .NET и другие фреймворки создают базовую библиотеку с основной функциональностью. Такая библиотека проверена создателями языка и обладает в значительной степени гарантированной надёжностью, с отсутствием багов.
Нет абсолютно никакой гарантии, что написанное кем-то ещё правильно или вообще будет нормально работать. Даже если всё корректно, это ли оптимальный способ решения проблемы? По крайней мере, когда вы пишете код сами, вы можете легко изменить его, исправить баги и повысить эффективность. Не должно быть особенно много багов в функции из 1 строчки.
Во-вторых, даже если логика в пакете правильная, меня поражает тот факт, что разработчики устанавливают зависимости на однострочные функции, которые сами должны уметь писать с закрытыми глазами. Если ты не можешь написать функцию left-pad, is-positive-integer или isArray за пять минут (включая время на поиск в Google), то ты вообще не умеешь программировать. Чёрт, любая из них может быть хорошим вопросом на собеседовании как проверка, умеет ли кандидат программировать.
В конце концов, связывание вместе разных API не является программированием. Это какая-то сумасшедшая форма хакинга зависимостей, которая включает в себя облака и перегруженность кодом и сложностями, реально не нужными.
Что ещё хуже, если в вашем коде или в коде сторонней библиотеки есть баг или код некорректно работает, то вы не будете знать, как отладить или исправить его, если вы не умеете программировать.
Каждый добавленный пакет прибавляет ещё одну зависимость к вашему проекту. Зависимости, по сути этого слова, — то, в чём вы нуждаетесь, чтобы код работал. Чем больше зависимостей, тем больше у вас точек отказа. Не говоря уже о большей вероятности ошибки: вы проверяли кого-нибудь из тех программистов, кто написал эти функции, от которых вы зависите ежедневно?
Примите зависимость для любой сложной функциональности, которую очень долго и дорого реализовать самостоятельно. Вещи вроде уровня доступа к базе данных (ORM) или клиента кэширования нужно устанавливать как зависимости, потому что они сложные и риск зависимости окупается экономией и эффективностью.
Но пожалуйста, ради любви ко всему, что представляет собой программирование, самостоятельно напишите проклятые базовые функции. Ставить зависимости на однострочные пакеты — это вообще рехнуться. Не верите? Просто спросите у разработчиков React, как у них прошла неделя, и не жалеют ли они о том, что сами не написали те 11 строк для набивки строки слева пробелами.
Итак, разработчики, время для серьёзного разговора. Вы уже наверное в курсе, что на этой неделе React, Babel и куча других популярных пакетов на NPM сломались. Причина довольно удивительная.
Простой пакет NPM под названием left-pad был установлен как зависимость в React, Babel и других пакетах. Модуль, который на момент написания этого поста, имеет 11 звёзд на Github (сейчас 323 — прим.пер). Весь пакет состоит из 11 простых строчек, которые реализуют примитивную функцию вставки пробелов в левой части строк. Если какие-то из ссылок когда-нибудь умрут, вот его код:
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
Что меня беспокоит, так это такое большое количество пакетов, где установлена зависимость от простой функции набивки строки пробелами, вместо того чтобы потратить 2 минуты и написать эту базовую функцию самому.Узнав о бедствии, которое случилось из-за left-pad, я начал исследовать экосистему NPM. И вот что обнаружил, среди прочего:
- Есть пакет под названием isArray, который скачивают 880 000 раз в день, 18 млн скачиваний в феврале 2016 года. У него 72 зависимых NPM-пакета. И вот его целая 1 строчка кода:
return toString.call(arr) == '[object Array]';
- Есть пакет под названием is-positive-integer (GitHub), который состоит из 4 строчек и которому на вчерашний день требовалось 3 других пакета для работы. Автор с тех пор провёл рефакторинг, так что теперь у пакета 0 зависимостей, но я не могу понять, почему это не было сделано сразу.
- Свежая установка Babel включает 41 000 файлов
- Чистый шаблон приложения на базе jspm/npm начинается c 28 000+ файлов
Всё это заставляет задать вопрос…
Мы разучились программировать?
В каком из параллельных миров вышеперечисленные решения являются наилучшими? Как сотни зависимостей и 28 000 файлов для пустого шаблона можно назвать чем-то ещё, кроме чрезмерной сложности и безумия?
Создаётся впечатление, что участники экосистемы NPM взрастили фетиш микропакетов. Вместо того, чтобы написать любую функцию или код, они как будто предпочитают установить зависимость на что-то написанное кем-то другим. Мне кажется, что вся работа программиста в экосистеме NPM сводится к написанию как можно меньшего количества кода, чтобы связать вместе существующие библиотеки, чтобы создать нечто новое, функционирующее уникальным образом для личных или коммерческих нужд.
Функции — это не пакеты
Функции слишком малы, чтобы попасть в пакет и зависимость. У чистых функций нет связи; это случайные фрагменты кода и ничего больше. Кому нужна зависимость от косинуса? Вместо этого нам бы по-настоящему понравилась зависимость от пакета «тригонометрия», который охватывает много хитрых функций, которые мы не хотим писать сами. Это гораздо больше похоже на то, как .NET и другие фреймворки создают базовую библиотеку с основной функциональностью. Такая библиотека проверена создателями языка и обладает в значительной степени гарантированной надёжностью, с отсутствием багов.
Проблема третьих лиц
Нет абсолютно никакой гарантии, что написанное кем-то ещё правильно или вообще будет нормально работать. Даже если всё корректно, это ли оптимальный способ решения проблемы? По крайней мере, когда вы пишете код сами, вы можете легко изменить его, исправить баги и повысить эффективность. Не должно быть особенно много багов в функции из 1 строчки.
Во-вторых, даже если логика в пакете правильная, меня поражает тот факт, что разработчики устанавливают зависимости на однострочные функции, которые сами должны уметь писать с закрытыми глазами. Если ты не можешь написать функцию left-pad, is-positive-integer или isArray за пять минут (включая время на поиск в Google), то ты вообще не умеешь программировать. Чёрт, любая из них может быть хорошим вопросом на собеседовании как проверка, умеет ли кандидат программировать.
В конце концов, связывание вместе разных API не является программированием. Это какая-то сумасшедшая форма хакинга зависимостей, которая включает в себя облака и перегруженность кодом и сложностями, реально не нужными.
Что ещё хуже, если в вашем коде или в коде сторонней библиотеки есть баг или код некорректно работает, то вы не будете знать, как отладить или исправить его, если вы не умеете программировать.
Боремся за уменьшение зависимостей
Каждый добавленный пакет прибавляет ещё одну зависимость к вашему проекту. Зависимости, по сути этого слова, — то, в чём вы нуждаетесь, чтобы код работал. Чем больше зависимостей, тем больше у вас точек отказа. Не говоря уже о большей вероятности ошибки: вы проверяли кого-нибудь из тех программистов, кто написал эти функции, от которых вы зависите ежедневно?
Примите зависимость для любой сложной функциональности, которую очень долго и дорого реализовать самостоятельно. Вещи вроде уровня доступа к базе данных (ORM) или клиента кэширования нужно устанавливать как зависимости, потому что они сложные и риск зависимости окупается экономией и эффективностью.
Но пожалуйста, ради любви ко всему, что представляет собой программирование, самостоятельно напишите проклятые базовые функции. Ставить зависимости на однострочные пакеты — это вообще рехнуться. Не верите? Просто спросите у разработчиков React, как у них прошла неделя, и не жалеют ли они о том, что сами не написали те 11 строк для набивки строки слева пробелами.