[Перевод] Почему repository в pom.xml — плохая идея
Где-то полгода назад я опубликовал туториал, посвящённый добавлению в проект библиотек, которых нет в репозиториях maven. Речь шла о маленьких проектах, и я порекомендовал ставить тег repository прямо в pom.xml, чтобы можно было собирать проект без необходимости править settings.xml.
В комментариях этот подход критиковали sshikov, igor_suhorukov, jbaruch и многие другие. Там же в комментариях мне дали ссылку на статью Брайана Фокса, в которой чётко и понятно изложено, чем чреваты repository в pom.xml. Статья 2009 года, но не потеряла актуальности до сих пор. Перевода на Хабре я не нашел — поэтому предлагаю вашему вниманию свой.
Есть один вопрос, который мне задают очень часто, и, думаю, пришло время изложить свои мысли по этому поводу в письменном виде, чтобы не приходилось повторять их снова и снова.
Вот он, этот вопрос: Куда класть пути к репозиториям: в помники или в settings.xml?
Короткий ответ: settings.xml.
Длинный ответ: По обстоятельствам.
Тут нужно рассмотреть два сценария: для энтерпрайза (программного обеспечения, которое недоступно извне) и общедоступного программного обеспечения.
Мы начнём с энтерпрайза.
Энтерпрайз
В случае с энтерпрайзом общепринятая практика — ставить какой-нибудь менеджер репозиториев наподобие Nexus. Он работает как прокси для всех внешних репозиториев, а также управляет внутренними.
Когда maven ищет артефакты, он ходит по перечню репозиториев, определённых в помниках и в settings.xml, пока не найдёт то, что ищет. Если в качестве репозитория в помнике указать ваш менеджер репозиториев, maven всё равно откатится к поиску в репозитории Central, когда не найдёт артефакты там.
Один из способов решить эту проблему — переопределить id репозитория Central и вписать туда адрес вашего менеджера репозиториев. Такое решение может подойти, но, чтобы не повторять процедуру для каждого проекта, делать это нужно в каком-то одном корпоративном pom файле. После переопределения Central вы попадаете на «Уловку-22». Для того, чтобы найти помник, в котором указан путь к репозиторию, нужно знать, где репозиторий, в котором этот помник находится. Закончится всё тем, что в любом случае придётся добавить этот репозиторий в settings.xml просто чтобы что-то вообще работало.
С простым переопределением Central есть и другие проблемы. Конкретно, этот способ не позволяет обрабатывать обращения к другим репозиториям, которые могут быть в транзитивных зависимостях проекта и редиректить запросы к ним. Это порождает проблемы: во-первых, замедляется сборка, так как maven обходит все внешниe репозитории в поисках артефакта… Возможно, он будет искать артефакт даже в ваших внутренниx репозиториях, в которых этого артефакта точно нет. Во-вторых, это означает, что что-то может собраться у одного разработчика и не собраться у другого. В-третьих, получается, что как организация вы понятия не имеете, откуда берутся ваши артефакты.
Вам, как организации, в большинстве случаев удобно, когда все разработчики используют одни и те же репозитории при сборке и все запросы проходят через один контролируемый механизм. Этого легче всего достичь с помощью записи mirrorOf * в settings.xml, которая будет редиректить все запросы на ваш менеджер репозиториев. В помнике mirrorOf определить нельзя. Примеры того, как выглядит хорошая настройка, можно посмотреть в этом разделе Nexus Book.
Если учесть все эти моменты, понятно, что определение репозиториев в pom.xml на самом деле не очень помогает и в основном только создаёт дополнительные проблемы.
Выше подразумевается, что ваши артефакты не имеют внешнего потребителя. Если это не так, то кроме первой категории, вы попадаете ещё и во вторую. (Категории не исключают друг-друга.)
Проекты с открытым кодом
Если вы выкладываете своё программное обеспечение в открытый доступ и его будет скачивать и собирать кто-то, кроме вас, тогда нужно учесть и другие моменты. Если все ваши зависимости есть в репозитории Central, тогда больше ничего делать не надо. Однако если ваши артефакты можно положить только в ваш собственный репозиторий (речь идёт, например, о SNAPSHOT версиях ваших родительских помников), или в репозитории третьих лиц, тогда со сборкой вашего кода у разработчиков будут проблемы. В этом и только в этом случае имеет смысл добавлять repository в ваши помники. Но тут есть побочные эффекты, о которых нужно знать.
- Записи, которые вы внесли, будут навечно отлиты в зарелизенных помниках. Это означает, что если урлы потом поменяются, все, кто использует ваши старые помники, получат битые ссылки, и им придётся выискивать рабочие ссылки вручную.
- Каждая из этих записей попадёт в их сборки, так как maven нужно будет просматривать их при поиске зависимостей. В данный момент maven не в состоянии понять, что зависимости вашего репозитория находятся в нём самом (а если учесть транзитивность, ситуация выглядит ещё хуже).
Если результат сборки — утилита (как Nexus), а не компонент, который будет использоваться как зависимость, то добавление repository в помник более-менее безопасно. В этом случае, маловероятно, что кто-то ещё будет зависеть от вашего артефакта в своей сборке напрямую, и изложенные выше опасения становятся беспочвенными, так как в новые версии кода скорее всего попадут правильные пути.
Если вы публикуете джарки, которые будут использоваться в сборке кем-то другим, тогда нужно подумать о том, чтобы выкладывать их и их зависимости в репозиторий Central. Тогда они всегда будут доступны всем пользователям, независимо от того, что случится с вашим репозиторием или урлами, и нет риска случайно внести новые репозитории в сборки. По этой же причине Central рано или поздно перестанет принимать помники с repository.
Итого
В сухом остатке имеем следующее. Если вам нужны воспроизводимые сборки и хороший контроль над происходящим внутри организации, используйте менеджер репозиториев, а также задавайте mirrorOf в settings.xml у всех сотрудников, чтобы указать адрес этого менеджера.
Если вы отдаёте исходники наружу и хотите, чтобы их удобно было собирать, рассмотрите возможность добавления repository в помник, но не подходите к выбору урла легкомысленно, мыслите стратегически, и используйте урл, который всегда будет под вашим контролем. Если урл придётся изменить, убедитесь, что вы всегда сможете отследить ошибки 404 и напишите соответствующие правила mod_rewrite для того, чтобы убедиться, что будущие сборки смогут найти подходящие артефакты.
P.S.
И в заключение небольшая байка из моей собственной жизни. Когда-то давно я поучаствовал в создании концепт пруфа одной интересной идеи. Сделано всё было на java, и деплоить код надо было естественно в среде заказчика, иначе — какой же это пруф :). Сборка была оформлена согласно рекомендациям лучших собаководов, репозитории подключались в settings.xml, артефакты лежали в Nexus — всё как в этой статье.
Но во время деплоя внезапно выяснилось, что на settings.xml, который используется при сборке, нам не дадут даже посмотреть, не говоря уже о редактировании оного. Энтерпрайз, секьюрити, все дела. И пришлось класть repository в помник. Репозитории для разработки и для CI были разные, и для того, чтобы как-то обработать эту ситуацию, сделали 2 профиля: один — с репозиториями для CI, который был дефолтным, а другой — с репозиториями для разработки, который помечался как дефолтный в settings.xml на машине разработчика. Эмоций, помню, мы тогда хлебнули изрядно. Вот так вот бывает.
Наша компания ищет:
- руководителя группы разработки
- технического руководителя проекта.