После недавнего удаления модуля на 11 строк кода из npm, которое сломало всю Node.js инфраструктуру, я по-новому взглянул на то, как в проектах на Go реализованы зависимости от других пакетов.
Изначально, при знакомстве с go я был крайне недоволен отсутствием возможности задавать зависимости от конкретных версий (зависимость указывается только от репозитория, т.е. от master ветки) - ведь апстрим может ломать обратную совместимость, и твой проект просто не соберется. Причем я сам с этой проблемой столкнулся, и это было очень неприятно.
К счастью, не я один страдал от этой недоработки, и для решения этой проблемы в go1.5 добавили экспериментальный vendoring зависимостей, который в 1.6 включили по-умолчанию.
Теперь появилась возможность сложить все зависимости в директорию vendor/
внутри своего проекта, и все утилиты go будут с ними корректно работать.
Тут возникла дилемма - добавлять ли vendor/
в git вместе с проектом?
Glide, популярная утилита для работы с зависимостями в go, которой я пользуюсь, дает следующие рекомендации:
- для библиотек не добавлять
vendor/
в VCS; - для утилит добавлять
vendor/
в VCS для обеспечения повторяемости билдов у пользователей.
Мысль о добавлении всех зависимостей в репозиторий моего проекта пугала меня, и казалась костылем. Однако после анализа своего опыта взаимодействия с менеджерами пакетов в других языках и по здравому размышлению о подходе go, я был вынужден принять решение с добавлением всех зависимостей в проект.
Решение это не идеальное, но создание очередного навороченного менеджера пакетов тоже не подарок, и проблем (как мы видим на примере того-же Python) с ним хватает.
А тут мы застрахованы и от удаления самого репозитория с нашей зависимостью, и от поломанной обратной совместимости. Кстати, насколько мне известно, все большие проекты работают именно по такой схеме - хранят все зависимости у себя.
При этом радует то, что для установки утилит с зависимостями в vendor/
в VCS
не нужен никакой менеджер зависимостей типа Glide/Godeps и т.п. - мухи отдельно,
котлеты отдельно. Пользователь просто делает go get my_package
и радуется.
А мы используем менеджер зависимостей по вкусу и тоже радуемся - все довольны.
В общем, на этом примере явно видна одна из главных особенностей Go, то, за что его можно одновременно любить и ненавидеть - он прагматичный до мозга костей.
Лично для меня это скорее достоинство.