Стендап Сьогодні
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
22.05.2025
Чим система залежностей Go гірша за node_modules?
Тека з модулями Node.js - node_modules
- є на цей час біблейським прикладом надмірної купи залежностей. Але я б не сказав, що ця проблема обмежується тільки Node.js чи тільки JS. Поки подивімося на Go.
В Go пакети завжди імпортуються за URL: import "github.com/leonid-shevtsov/omniwope"
. Що сидить за цим URL? Який формат файлу мають пакети Go? Ооо… Пакет Go завжди є репозиторієм системи контролю версій. (Звісно, найчастіше Git, але не обовʼязково.) Таким чином, мова Go не має ніякого “пакетного формату файлів”, а просто завантажує зміст, як це робить git clone
. Та ще й перекладає питання версіювання на репозиторій.
Це все з одного боку спрощує життя. В Go немає проблеми сквотингу (хоча дехто відхопив собі смачне імʼя github.com/lib/pq, наприклад.) Немає централізованого сервісу — можна хоч на власному домені публікувати. Питання авторизації та приватних пакетів теж легко розвʼязується через репозиторій. Через все це я люблю Go modules
.
(Ще цікавий момент: мажорна версія змінює URL пакету. Хоча це тільки домовленість, та я багато разів зустрічав несумісні зміни з тією ж мажорною версією.)
А тепер, величезний недолік. Змістом пакета є зміст репозиторію. Немає ніякої можливості сказати, що деякі файли не потрібні. Коли ти встановлюєш пакет Go, то тягнеш всю-всю документацію, ілюстрації, тестові файли — просто все. Наприклад: є github.com/pierrec/lz4/v4 із 40 Мб тестових архівів. І всі вони будуть сидіти в тебе на диску, в кеші CI тощо.
Те ж саме стосується й транзитивних залежностей. Та що мене особливо дратує — навіть якщо транзитивна залежність потрібна тільки для оголошення типу, все одно всі її файли будуть завантажені в Go modules. Ну а як інакше, коли тип є частиною коду? Цього можна частково уникнути, якщо оголошувати інтерфейси на боці споживача — але все одно вони часто спираються на конкретні типи. Або, пакети, потрібні для тестів транзитивних залежностей, теж завантажуються. Наприклад, пакет testfixtures підтримує БД Clickhouse. Мені вона зовсім не потрібна — та сам пакет не має на неї залежність. Але його тести — мають! Та оскільки тест сидить в тому ж самому репозиторії, то пакет Clickhouse стає транзитивною залежністю вже мого застосунку. І це тільки один приклад з безлічі.
Заради справедливості: цього напливу залежностей можна уникнути, якщо робити go mod vendor
- тоді копіюється тільки код, потрібний для головного пакета. Але насправді це допомагає тільки якщо у вас цей vendor
ще й доданий до Git. Бо інакше будете тримати локально як vendor
, так і окремо всю купу — щоб його побудувати.