Ад зависимостей

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

Итак, проблема (которой пока что даже и нет): пакет «Пакет1» зависит от библиотеки «Файлы», «Пакет2» тоже зависит от библиотеки «ВременныеФайлы», который зависит от библиотеки «Файлы». Здесь побитый граблями лоб нам как бы намекает: «бро! Пакет1 может хотеть одни Файлы, а Пакет2 в итоге — другие файлы! Притом, что в системе могут быть установлены вообще третьи файлы». Беда. Как эту беду решает npm (откуда, как я понял, мы черпаем основное вдохновение): в каталоге текущего проекта создаём каталог «чётотам_modules», в него рекурсивно напихиваем библиотеки с нужными версиями. Это здорово, когда мы пишем здоровенное серверное приложение или когда ковыряем какой-либо учебный проект. Но, ё-моё! Если 99% моих скриптов похожи вот на это:
[code lang=»odines»]
#Использовать Почта
#Использовать Файлы

Файлы.Скопировать(«Отсюда», «Сюда»);
Почта.Написать(«Всё хорошо»);
[/code]

Мне по большому счёту всё равно, какой версии у меня «Почта» и какой версии у меня «Файлы», если там есть «Скопировать» и «Написать». Откуда я беру «Скопировать» и «Написать»? Вот я сижу и в «ТекущаяДата()» пишу свой код. В этот «Новый МоментВремени(ТекущаяДата())» у меня есть определённая СТАБИЛЬНАЯ версия библиотеки — я начинаю использовать её, прописываю в зависимости её версию, устанавливаю её глобально в систему. Честно! Глобально в систему! Все мои скрипты начинают использовать эту библиотеку. Все скрипты, которые используют другие библиотеки, использующие эту библиотеку, тоже используют эту библиотеку ЭТОЙ версии. Я ставлю обновление библиотеки — все-все-все скрипты теперь используют новую улучшенную версию библиотеки.

Здесь есть справедливое «НО» — обновление может сломать мои скрипты. Однако человечество уже придумало инструмент, который при должном подходе решает этот вопрос. Это семантическое версионирование.

Семантическое версионирование идеологически гарантирует, что в пределах одной мажорной версии у меня ничего не сломается. То есть, если у меня есть одна зависимость «1.0.1» и другая «1.1.2», то я могу глобально держать ТОЛЬКО «1.1.2» и всё будет работать. Если у меня есть зависимости «1.0.1» и «2.1.0», то у меня глобально должны стоять ДВЕ версии — по одной последней версии внутри каждой мажорной.

Подитог: глобально надо хранить не ОДНУ последнюю версию, а последнюю версию КАЖДОГО мажорного релиза. Потому что по сути своей это РАЗНЫЕ библиотеки.
По сути, мы полагаемся в данном случае на версию «Интерфейса библиотеки», оставляя в свободном полёте «версию реализации интерфейса». Примеры из жизни, за которыми далеко ходить не надо: gtk2 и gtk3 — это РАЗНЫЕ платформы, .Net 4.0 и .Net 4.5 — это РАЗНЫЕ платформы. В системе одновременно стоят и gtk2, и gtk3, одновременно работают приложения и на той, и на другой платформе, однако обновление gtk2 повлияет на ВСЕ приложения, его использующие.

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

Проблема 2: Допилки на местах. В новом проекте я хочу не стандартную библиотеку, а её, но с парой своих вставок.
Решение: Тут уже никакого версионирования по большому счёту. Либо делаем свою библиотеку, вставляем свою допилку и версионируем по-своему (привет, поставки 1С), либо копируем библиотеку локально и не обновляемся вообще (привет, снятие с поддержки в 1С).

Проблема 3: Вот я починил ошибку и хочу поделиться кодом. Беда тут в том, что скачанные библиотеки никоим образом не привязаны к гиту и быстро выявить, что же было допилено, у человека на месте не получится.
Решение: Выход тут только один — архивируем библиотеку целиком, высылаем разработчикам библиотеки, они пусть сравнивают с выпущенной версией и выявляют изменения.
Лучше, конечно, чтобы здесь был применён вариант из пункта выше — форкнуть библиотеку и использовать в проектах свою доработанную версию. Но это совсем мечты пока что.

Итог.
Бешеный поток мыслей по изобретению велосипеда сводится к простому: хочу хранить глобально библиотеки в разрезе мажорных релизов. Хочу такую организацию локального каталога modules: никакой бешеной вложенности, храним на одном уровне последние версии каждого мажорного релиза.

На этом всё. Сейчас надо посмотреть, как что уже работает, и внести предложения на этот счёт.


Comments are closed.