?

Log in

Previous Entry | Next Entry

Я решил один раз высказать всё, что я думаю по поводу использования Apache Maven, ибо устал повторяться в регулярных обсуждениях этого вопроса. Плюсы описывать не буду, они всем известны.

Итак, Apache Maven.

Что он представляет собой в теории. Основывается на объектной модели проекта, управляет сборкой, документированием, созданием артефактов. Имеет определенный жизненный цикл (о нем ниже). Все действия осуществляются с помощью плагинов. Что особенно хорошо – позволяет отслеживать зависимости от библиотек, скачивать их (а также все необходимые им) из интернета.

Посмотрим на жизненный цикл сборки:

ФазаОписание
validateПроверка на корректность и наличие всей необходимой информации
initializeИнициализация сборки – установка свойств, создание директорий и т.п.
generate-sourcesГенерация исходников
process-sourcesОбработка исходников (например, фильтрация, установка внутри каких-либо значений)
generate-resourcesГенерация ресурсов
process-resourcesОбработка ресурсов, копирование их в директорию для упаковки
compileКомпиляция исходного кода
process-classesПост-обработка классов, например, для bytecode enhancement
generate-test-sourcesГенерация тестовых исходников
process-test-sourcesОбработка тестовых исходников
generate-test-resourcesГенерация тестовых ресурсов
process-test-resourcesОбработка тестовых ресурсов
test-compileКомпиляция тестовых классов
process-test-classesПост-обработка тестовых классов
testВыполнение тестов
prepare-packageПодготовка к сборке
packageСборка артефакта
pre-integration-testПодготовка к интеграционным тестам
integration-testИнтеграционные тесты
post-integration-testОбработка после интеграционных тестов, например, удаление данных и т.п.
verifyЛюбые проверки, связанные с качеством, принятие решения «выпускать/не выпускать» артефакт
installУстановка в локальный репозиторий
deployРазвертывание, публикация в глобальном репозитории


Этот жизненный цикл хорошо покрывает типовой проект. Ключевое слово тут – типовой. Что это означает на практике?

Представьте себе, что для сборки надо выполнить следующую последовательность действий:


  1. Собрать исходный код
  2. Обратиться к некой базе данных, выгрузить оттуда данные в бинарном формате.
  3. Обработать эти данные с помощью native-приложения, которое сгенерирует много xml-файлов
  4. Сгенерировать по xml-файлам исходники
  5. Cобрать сгенерированные исходники с использованием нашего исходного кода, который был собран на первом шаге


Всё очень просто, только последовательность шагов перепутана по сравнению со стандартным жизненным циклом.

И как на это реагирует maven? А точно так, как это описано было у Булгакова: «А он глаза вылупил и молчит!»

Жизненный цикл maven просто не приспособлен для решения подобных задач. Он не может понять, зачем компилировать два раза, а в промежутках подготавливать данные, обрабатывать и генерировать исходники.

Дальше. Управление зависимостями. В теории всё замечательно – описал библиотеки вместе с нужными версиями, ну и всё само скачалось. Вот только вопрос: откуда скачалось?

Теоретически есть большой репозиторий, где лежат самые популярные библиотеки. А если там не того, что надо? Тогда предлагается прописать репозиторий производителя библиотеки. Замечательно. А если у производителя его нет? Тогда можно поискать специальными сервисами – может, библиотека где-то всё таки лежит? А если нет?

Представьте ситуацию. Библиотека не поддерживается с 2004 года. У нас есть исходники, в которые мы внесли достаточно много изменений. Вопрос. Что делать с такой библиотекой? Где ее искать?

Вариант, собственно, один. Организовывать свой репозиторий. Ради одной библиотеки. Других вариантов maven не предлагает.

Дальше, насчет «всё само скачалось». Мы уже привыкли к этому и даже не замечаем, что очень многие действия требуют подключения к интернету. А вот теперь представьте, что подключения нет и не предвидится. Вопрос. Откуда скачаются все необходимые библиотеки? «А он глаза вылупил и молчит!..»

Кстати, ситуация далеко не невозможная. В любом банке отсутствие доступа к интернету – норма. Особенно для пришедших со стороны разработчиков, и неважно, что они пришли внедрять систему. Более того, даже во многих IT-компаниях нет прямого доступа к интернету. А это означает организацию зеркала внешнего репозитория (отдельная служебная записка и не одна), его регулярное обновление (отдельно выделенный человек, согласованная процедура) и т.д. и т.п.

Более того, не только библиотеки – даже плагины не скачаются. Их maven тоже берет из репозитория. Т.е. без доступа в интернет не то что что-то сложное – простейший HelloWorld скомпилировать и запустить не удастся.

Не, теоретически maven умный, он все скачанные библиотеки кеширует в локальном репозитории. Но, простите, чем локальный репозиторий отличается от ситуации, когда библиотеки просто лежат рядом с исходниками в одной выделенной папке?

Промежуточный итог. maven по своему подходу концентрируется на том, что надо сделать. И хорошо концентрируется. Но, к сожалению, в нем заложен только один вариант того, как это надо делать. Жизненный цикл – такой и никак иначе. Библиотеки – из репозитория и никак иначе. Действия – плагинами и никак иначе.

Теперь о недостатках maven как инструмента.

Абсолютно все действия в нем выполняются плагинами. И я как пользователь нахожусь в безальтернативной зависимости от качества этих плагинов. Я неоднократно наталкивался на ошибки, которые я не мог обойти иначе как повторить все нужные действия вручную.

Например, мне однажды не удалось сгенерировать классы по двум wsdl-файлам, так, чтобы они оказались в разных пакетах. Плагин позволяет указать несколько wsdl – но генерирует классы в одном пакете и по каждому wsdl в отдельности. В результате все технические классы типа ObjectFactory остаются от последнего обработанного wsdl. Сконфигурировать два вызова плагина на разных стадиях можно – но на более поздней плагин просто не отрабатывает. Причем я подозреваю, что дело не в плагине – точно такая же ситуация наблюдалась и с моим собственным плагином, т.е. это поведение maven-а. Возможно, сейчас это уже не так, но три года назад я убил на это два дня и в результате решил задачу, сгенерировав исходники вручную и выложив их в систему версионного контроля.

И это далеко не единичный случай. Ошибки в плагинах есть, от этого никуда не деться. А обходные маневры maven затрудняет до крайности.

Следующий недостаток – maven крайне плохо себя чувствует при выходе за пределы мира Java. У меня перед глазами есть один проект. Крупная система, более 20 модулей на C++ и Java, C++ код собирается под 4 версии Linux и две Windows, причем под 32 и 64 бита. В компании построен сборочный кластер, сборка написана на make. Всё работает. И вот это всё начинают переводить на сборку maven-ом на том основании, что он хорошо умеет управлять зависимостями. Через полтора года мучений оказывается, что зависимостями он умеет управлять только для java-кода, а в данном случае его очень немного. Для сборки остальных же артефактов приходится писать более десятка плагинов. Два модуля в конце концов удается перевести на сборку maven-ом, общее время сборки системы при этом вырастает в несколько раз. Причем занимается этим не дилетант – товарищ очень серьезный специалист по maven.

Третий недостаток я уже упоминал – зависимость от соединения с интернетом. Т.е. при переходе куда-то, где нет соединения, для работы maven необходимо будет кроме непосредственно кода проекта переносить и локальный репозиторий. Причем заметьте, весь репозиторий. Не только то, что нужно конкретному проекту, но вообще всё, что накачал maven на данной рабочей станции при обработке всех проектов (мне приходилось переносить репозитории размером в 500Мб). Или же производить детальный анализ зависимостей и вручную (!) удалять всё лишнее.

Четвертый недостаток, тоже уже упомянутый – жизненный цикл. Крайне жесткий. Возможность изменения? Я такой не знаю.

И о достоинствах – так ли они важны на самом деле?

Основное, что все и всегда говорят, когда идет речь о maven – управление зависимостями. Указали библиотеку, он ее подтянул, а заодно и все, необходимые для работы.

На мой взгляд, это является достоинством в том случае, если добавлять библиотеки раз в час. Ну, раз в день. В моем текущем проекте мы добавили 4 (че-ты-ре!) библиотеки за последний год. У одной из них была зависимость – еще одна библиотека. Всё.

Крупные проекты, как правило, крайне консервативно относятся к добавлению новых библиотек. И даже к обновлению версий существующих. Просто потому, что надо быть уверенным, что такая замена не сломает функционала, уже работающего у клиента. На обновление одной библиотеки еще можно уговорить. Но когда по зависимостям тянется обновление версий еще пяти и добавление трех новых... Я очень хорошо помню, как на переход с версии Java 1.3.1_07 на 1.3.1_09 в боевой системе было потрачено два месяца. И переход состоялся только потому, что в 1.3.1_07 в виртуальной машине был найден баг, который у нас регулярно вылезал. Мы перешли ровно на ту версию, в которой этот баг был исправлен, хотя после нее уже было выпущено несколько следующих. И два месяца потратили на доскональное полное тестирование.

Таким образом, может оказаться, что библиотеки добавляются крайне редко. И отслеживать их зависимости попросту не нужно – это будет делаться один раз, в момент добавления библиотеки. Четыре раза в год – не такая серьезная активность, чтобы ее автоматизировать.

Итого.

maven имеет нишу, в которой он хорошо работает. Это типовые java-проекты, динамично развивающиеся, использующие последние версии распространенных библиотек. В этих случаях maven способен дать преимущества.

И в то же время есть проекты, в которых maven способен принести существенно больше проблем, нежели пользы. Это проекты сложной структуры, с жизненным циклом сборки, отличающимся от стандартного, использующие нестандартные библиотеки, native-инструментарий, включающие native-код. В общем, любые проекты, требующие выходы за жесткие рамки maven-овского «как», что немедленно оборачивается головной болью.

Таким образом, стандартное мнение «используй maven и будет тебе счастье», высказанное до выяснения всех подробностей проекта, свидетельствует прежде всего о недостатке опыта. Автор такого высказывания забывает – или же просто не предполагает! – что существуют нетиповые проекты. Впрочем, он не одинок – в одной компании с ним находятся и разработчики самого maven-а.

Comments

Val Urbanskyi
Aug. 9th, 2012 05:27 pm (UTC)
У меня нет тут аккаунта, так что уж не взыщите.
Хорошо написали, но похоже вы таки не поняли суть мавена. он достаточно гибок и рассчитан на проекты практически любой сложности. Просто в отличии от подобных, например анта, это декларативний инструмент. А это накладывает определенные ограничения на то как вы будете декларировать. :) понимаете? Вам нужно дважды компилить, разбейте сорцы на два модуля, укажите зависимости и будет вам счастье. :)
Мавен как раз тем и хорош что заставляет делать проекты простыми и быстрочитабельными. Он не допускает "творчества" в билде. Что, согласитесь, скорее плюс, давайте творить в коде, а не в билд скрипте.
Злой этот ваш ЖЖ, похоже уже у меня есть эккаунт. :)
skipy_ru
Aug. 10th, 2012 11:31 am (UTC)
> Вам нужно дважды компилить, разбейте сорцы на два модуля, укажите зависимости и будет вам счастье. :)

Я сильно упростил описание ситуации. Надо было на maven перевести ant-скрипт килобайт на 30, который в основном состоял из вызовов native-утилит, вплоть до компиляции native-кода и создания новых утилит.

Поверьте, я хорошо понимаю суть maven, я с ним работал несколько лет и вообще являлся инициатором его внедрения в проекте (практически типовом, во всяком случае сначала). Да, структурированием можно решить ряд задач, которые не решаются в лоб. Но мне совсем не улыбается делать тридцать-сорок модулей, когда всё это я могу сделать в ant линейно. На maven можно реализовать проекты практически любой сложности, но он на них совсем не расчитан.

То, что Вы считаете "творчеством в билде" - это и есть та гибкость, которой maven-у категорически не хватает. Я на ant могу описать любой процесс, любой сложности и с любой последовательностью действий. И иногда это реально надо.
Val Urbanskyi
Aug. 10th, 2012 06:56 pm (UTC)
Ну тут имеет смысл определится а зачем вы переводили с анта на мавен? Если сделать проект проше, мне кажется, структурирование тут не помешает. Правда?
Зечем вообше нужно чтото там структурировать? Я всегда думал, чтобы сделать чтото читабельным, так легче понять. Нет? Если такой задачи у вас не было, не нужно ничего никуда переводить. Правило помните? Работает, не трогай.

Не нужно тут гибкости. Я никогда не понимал, почему билд может быть сложнее чем приложение он должен собирать. Вот вы наверное сможете ето обьяснить? (Мне правда интересно.)