Гігієна залежностей: чому важливо стежити за чистотою коду, який ми підключаємо у свої проєкти

Перекладено ШІ 0 stitcher.io 30 липня, 2026

Чи замислювалися ви, скільки зайвого коду потрапляє у ваш Laravel-проєкт через сліпу довіру до package managers? Розповідаємо про важливість «гігієни залежностей» та способи очистити composer.json від непотрібних polyfills.

Оновлення: цей допис викликав жваві дискусії. Спершу я написав окремий текст із продовженням, але згодом вирішив зібрати все в одному місці. Тож я додав до цієї статті розділ, де розглядаю аргументи, що з'явилися в мережі.

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

У роботі я зустрів проект, що потребував paragonie/sodium_compat. Це логічно: пакет додає підтримку функцій sodium, які з’явилися «з коробки» лише в PHP 7.2. Але був нюанс: мінімальною вимогою самого проекту вже був PHP 7.3! Отже, хоча paragonie/sodium_compat встановлювався щоразу, він фактично був непотрібним. Я створив issue, і зрештою розробники видалили цю залежність.

Сама по собі зайва залежність не є критичною проблемою. Але з огляду на останні інциденти в NPM виникає питання: наскільки ми усвідомлюємо, від якого коду залежимо? Чи не занадто сліпо ми довіряємо всьому, що підтягує менеджер пакетів?

Я написав скрипт для сканування проектів, що використовують популярні polyfills та compatibility packages:

  • paragonie/sodium_compat
  • paragonie/random_compat
  • symfony/polyfill-php70
  • symfony/polyfill-php70
  • symfony/polyfill-php71
  • symfony/polyfill-php72
  • symfony/polyfill-php73
  • symfony/polyfill-php80
  • symfony/polyfill-php81
  • symfony/polyfill-php82
  • symfony/polyfill-php83
  • symfony/polyfill-php84

Кожного разу, коли проект вимагав один із цих пакетів без реальної потреби (згідно з даними Packagist та вимогами до версії PHP), я це фіксував.

Із 1554 просканованих проектів 229 мали зайві залежності. Це близько 15%. Я надіслав PR кожному з них, щоб виправити це.

Звісно, це лише невелика частина екосистеми PHP. Проте цифра достатньо значуща, щоб замислитися: чи достатньо ми перевіряємо код, на який покладаємося? Я не вважаю, що package managers — це зло, але вони точно роблять нас дещо… ледачими. Можливо, нам варто приділяти більше часу розумінню того, що саме ми встановлюємо?

Інший приклад — symfony/polyfill-mbstring. Він є чи не в кожному PHP проекті. Я навіть не знаю, звідки він береться, поки не запущу composer why (до речі, дуже корисна команда). Ми просто звикли: якщо ти працюєш із PHP, symfony/polyfill-mbstring десь та й випливе. Я не зміг додати його у свій скрипт, оскільки він замінює опціональне розширення PHP і не прив’язаний до конкретної версії мови (хоча, чесно кажучи, mbstring зазвичай встановлено за замовчуванням у більшості середовищ).

Утім, є спосіб відмовитися від таких пакетів: додати конфігурацію replace у ваш composer.json:

{
    "replace": {
        "symfony/polyfill-php54": "*",
        "paragonie/sodium_compat": "*",
        "symfony/polyfill-mbstring": "*"
    }
}

Це вказує composer, що ваш проект уже містить ці пакети, тому їх не потрібно завантажувати. Це трохи незручно, і більшість розробників не переймаються такими налаштуваннями. Але без цього трюку ви майже гарантовано отримаєте ці залежності, бо в дереві проектів завжди знайдеться щось, що посилається на symfony/polyfill-mbstring.

Чи є в цьому проблема? Поки що ні. Хіба що одного дня станеться supply-chain attack, які ми вже не раз бачили в екосистемі NPM. Зручно мати polyfill про запас, але чи це вагома причина для ризику?

Можливо, нам час почати дбати про «гігієну залежностей»? Діліться думками в коментарях або в Discord!

Продовження

Після публікації допису я отримав багато коментарів. Хочу відповісти на основні тези тут.

Щодо sodium зокрема

Більшість дискусій зосередилася саме на paragonie/sodium_compat. Шкода, що це відволікло від основної ідеї, і частково це моя провина. Я спочатку не врахував, що хоча ext-sodium є вбудованим розширенням з версії PHP 7.2, він не завжди увімкнений за замовчуванням у Linux та Windows. Чому саме так — питання відкрите.

Хоча мій аргумент про гігієну залежностей залишається чинним, із paragonie/sodium_compat ситуація складніша. Як розробник open source, я все ж вважаю, що краще дати користувачеві можливість самому вирішувати на рівні системи, чи використовувати ext-sodium, чи paragonie/sodium_compat, замість того, щоб бібліотека примусово завантажувала сторонній пакет. Трюк із replace працює, але він не є обов’язковим, і на практиці мало хто ним користується.

Можливості composer

Багато хто запропонував розширити схему composer.json, щоб пакет міг сам оголошувати себе зайвим при виконанні певних системних вимог. Це могло б виглядати так:

{
    "name": "paragonie/sodium_compat",
    # …
    "replaced-by": {
        "ext-sodium": "*",
        "php": "^7.2"
    }
}

Зауважу: зараз у composer такої можливості немає. Ідея цікава, хоча можуть бути причини, чому її важко реалізувати. Я планую розпитати про це Jordi (автора Composer).

Про гігієну пакетів

Моє головне побоювання — це надлишковий код на мільйонах серверів, де він не потрібен (paragonie/sodium_compat має близько 140 тисяч завантажень щодня). Сьогодні це не проблема, але так само було і з пакетами NPM до того, як вони стали векторами атак. Ми не повинні ставитися до цього легковажно.

На мою думку, проблема поглиблюється тим, що бібліотеки додають ці пакети в залежності не замислюючись. Потім ці бібліотеки стають частиною інших проектів, і в результаті «залежність залежності» опиняється там, де їй не місце. «Хороша гігієна» — це не нав'язувати polyfills на рівні бібліотек, а дозволяти кінцевому розробнику обирати найкращий підхід для його системи.

Популярні

Інше, що варто прочитати

14 Оновлено 26 червня, 2026

Локальні моделі та їх скоупи в Laravel за допомогою атрибута Scope

В Laravel 12 ми отримали можливість використовувати новий підхід для визначення локальних скоупів у моделях Eloquent. Дізнайтеся, як новий атрибут #[Scope] спрощує цей процес і зберігає ваші назви методів незмінними

16 Оновлено 26 червня, 2026

Простий пакет RabbitMQ для Laravel

Вам цікаво дізнатися, як спростити інтеграцію RabbitMQ у вашому Laravel-додатку? У нашій статті ми розглянемо пакет Simple RabbitMQ, який дозволяє легко налаштувати багатозʼєднання, публікувати повідомлення та обробляти черги за допомогою простого синтаксису. Читайте далі, щоб дізнатися більше!

11 Оновлено 26 червня, 2026

Laravel: шлях до створення справді дієздатних AI-агентів

Чи готові ви підвищити ефективність своїх проектів на Laravel і спростити інтеграцію штучного інтелекту? У нашій статті ви дізнаєтеся, як Vizra ADK може революціонізувати ваш підхід до розробки, розширюючи можливості, забезпечуючи тестування та надійність для ваших AI-агентів