Итак, 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 | Развертывание, публикация в глобальном репозитории |
Этот жизненный цикл хорошо покрывает типовой проект. Ключевое слово тут – типовой. Что это означает на практике?
Представьте себе, что для сборки надо выполнить следующую последовательность действий:
- Собрать исходный код
- Обратиться к некой базе данных, выгрузить оттуда данные в бинарном формате.
- Обработать эти данные с помощью native-приложения, которое сгенерирует много xml-файлов
- Сгенерировать по xml-файлам исходники
- 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-а.
Использование Apache Maven
August 9 2012, 16:43:20 UTC 8 years ago
August 9 2012, 17:16:29 UTC 8 years ago
August 9 2012, 17:27:27 UTC 8 years ago
Хорошо написали, но похоже вы таки не поняли суть мавена. он достаточно гибок и рассчитан на проекты практически любой сложности. Просто в отличии от подобных, например анта, это декларативний инструмент. А это накладывает определенные ограничения на то как вы будете декларировать. :) понимаете? Вам нужно дважды компилить, разбейте сорцы на два модуля, укажите зависимости и будет вам счастье. :)
Мавен как раз тем и хорош что заставляет делать проекты простыми и быстрочитабельными. Он не допускает "творчества" в билде. Что, согласитесь, скорее плюс, давайте творить в коде, а не в билд скрипте.
Злой этот ваш ЖЖ, похоже уже у меня есть эккаунт. :)
August 10 2012, 11:31:43 UTC 8 years ago
Я сильно упростил описание ситуации. Надо было на maven перевести ant-скрипт килобайт на 30, который в основном состоял из вызовов native-утилит, вплоть до компиляции native-кода и создания новых утилит.
Поверьте, я хорошо понимаю суть maven, я с ним работал несколько лет и вообще являлся инициатором его внедрения в проекте (практически типовом, во всяком случае сначала). Да, структурированием можно решить ряд задач, которые не решаются в лоб. Но мне совсем не улыбается делать тридцать-сорок модулей, когда всё это я могу сделать в ant линейно. На maven можно реализовать проекты практически любой сложности, но он на них совсем не расчитан.
То, что Вы считаете "творчеством в билде" - это и есть та гибкость, которой maven-у категорически не хватает. Я на ant могу описать любой процесс, любой сложности и с любой последовательностью действий. И иногда это реально надо.
8 years ago
August 9 2012, 18:40:35 UTC 8 years ago
August 9 2012, 19:36:49 UTC 8 years ago
August 9 2012, 19:57:15 UTC 8 years ago
Мавен и выезжает на том, что ниша типовых проектов достаточно большая.
August 10 2012, 04:11:44 UTC 8 years ago
* Сложные вещи почти всегда проще писать на ant или java. Maven поддерживает такое внедрение, и это работает. Плюс некоторые сложные сборки можно делать при помощи maven assembly plugin. Хотя и там не все так просто и есть ограничения.
* Иметь проксирующий репозиторий это правильно. А иначе можно очень сильно огрести когда: нет интернета, репозиторий внешний лежит, удалили библиотеку из внешнего репозитория, нет новой версии библиотеки на внешнем репозитории. Плюс проксирующий репозиторий очень сильно повышает вытягивание библиотек в локальный репозиторий. Я в последнее время активно использую nexus.
* Никто не заставляет вас использовать внешние репозитории для maven. Я в одном из проектов держал репозиторий в папке lib проекта. В pom файле я просто прописал путь к этому репозиторию и все работало довольно неплохо.
* Скорость maven оставляет желать лучшего. Реально медленно после ant. Но вроде бы в 3 версии обещали ускорить, плюс сделать поддержку многопоточной сборки. Но я прироста особого не увидел. Кстати, есть мнение что maven можно запустить демоном с инициализированным рунтаймом, и подсовывать ему команды. Вроде бы должно быть быстро. Но я тут не копал.
* В maven очень легко словить jar hell. Просто некоторые версии библиотек могут транзитивно вытягивать разные версии одной и той же библиотеки. И тут надо выбирать и делать exclude. Это немного утомляет.
August 10 2012, 11:36:55 UTC 8 years ago Edited: August 10 2012, 11:37:13 UTC
Как интересно! А можно пример?
А в остальном согласен.
8 years ago
8 years ago
August 11 2012, 08:10:27 UTC 8 years ago
Про отсутствие доступа к интернету в 21 веке читать смешно. Неужели такое действительно бывает? В каких IT-компаниях нет доступа к интернету? Если в организации хотя бы несколько проектных команд используют мавен, нужен репозиторий (типа Artifactory или Nexus), который возьмет на себя роль прокси между внешними репозиториями и вашим локальным репозиторием. Нет какой-то библиотеки в центральном репозитории или еще где? Залейте ее в свой корпоративный и будет вам щастье.
Мавен прекрасно себя показывает в том случае, если есть несколько проектов, которые завязаны на один проект (ядро системы). В этом случае при разработке используется т.н. snapshot-репозиторий, куда деплоятся артефакты сборки ядра, а все остальные проекты подтягивают свежую версию каждый раз при сборке. Как вы сделаете такое с помощью анта?
В общем, не хочется разводить здесь holy war, и в принципе я соглашусь с тем, что нужно понимать какие преимущества (и недостатки, куда же без них) несет использование той или иной системы сборки проекта.
August 13 2012, 08:46:24 UTC 8 years ago
Вот именно. Четкий цикл. Усредненный, представляющий собой представление разработчиков maven о том, как надо организовывать сборку. Однако, как известно, корова утонула в речке, где в среднем ей было по колено. И если мой жизненный цикл не совпадает с представлением maven - я с ним намучаюсь.
Если нужна дополнительная конфигурация - пожалуйста. Используйте gmaven плагин, antrun плагин, exec плагин, в конечном итоге, напишите свой (если очень нужно).
Знаете, как это называется? Мы сами себе создаем трудности, а потом героически их преодолеваем. Зачем мне возиться с maven-ом, если всё равно половину я сделаю на ant?
Про отсутствие доступа к интернету в 21 веке читать смешно. Неужели такое действительно бывает? В каких IT-компаниях нет доступа к интернету?
Я не называю компанию только потому, что они нервно реагируют на все мои комментарии с их упоминанием. Могу сказать только, что интернета с 9 до 19 не было не только у обычных разработчиков, но и у руководителей подразделений. Более того, из-за этого мы два с половиной месяца разрабатывали интеграцию с одной платежной системой, сорвав все сроки (реально работы нам было дня на 4). Просто потому, что мы тестировались утром, до 9 часов, и вечером, после 19. Один запуск утром, ошибка, исправление, следующий запуск вечером.
И это не единичный случай. В норме доступа к интернету, даже у разработчиков, нет в банках. Я сейчас плотно работаю с несколькими и не знаю, что бы мы делали, сиди мы на maven-е. Нам постоянно приходится отлаживаться на месте. А мы там даже описание полученной ошибки посмотреть не можем.
при разработке используется т.н. snapshot-репозиторий, куда деплоятся артефакты сборки ядра, а все остальные проекты подтягивают свежую версию каждый раз при сборке. Как вы сделаете такое с помощью анта?
Если реально нужен именно артефакт - общая директория хранения, монтируемая у разработчиков. А так - через svn:externals все нужные подпроекты монтируются к разрабатываемому, сборка строится обычным образом (сначала собрали библиотеку, потом свой код, библиотека собирается один раз в начале).
Еще раз. Я понимаю, что есть ситуации, когда maven работает хорошо. Если бы их не было - было бы странно его использовать. Я всего лишь хочу сказать, что ЕСТЬ ситуации, когда maven работает плохо. Горячие сторонники maven утверждают, что таких ситуаций нет и maven - панацея.
8 years ago
7 years ago
August 14 2012, 09:07:35 UTC 8 years ago
Как исключение, стоит вспомнить обновление снэпшотов различных модулей проекта. Что при достаточно большом географическом/административном разбросе команды должно "значительно упростить процесс разработки и интеграции". На деле же, при 50+ относительно часто (от ~10 раз в день, до раза в неделю) обновляющихся модулях, мы получаем регулярные ошибки компиляции, поврежденные jar в nexus (это скорее проблема связки bamboo-nexus, но легче от этого не становится) и необходимость ждать по 30 минут-часу, пока пройдет update dependencies + force update snapshots (nexus не всегда может быть расположен в вашей локальной сети, а интернет не всемогущ ;) ) и т.п.
А необходимость носить с собой архив репозитория - вообще смерти подобно. 500 Мб это еще цветочки. к тому же, если я ничего не путаю, мавен так и не научился чистить локальный репозиторий от старых билдов у snapshot'ов. Что дает возможность локальному репозиторию расти геометрически. Можно, конечно, вместо очередного обновления зависимостей создать новый локальный репозиторий, а потом архивировать его. Но это, согласитесь, не решение проблемы.
Привязка к интернету (и аргументы по поводу двадцать-какого-бы-то-ни-было века) - это то, с чем я вообще никак не могу примириться.
В целом же я с вами полностью согласен. Спасибо за хорошо сформулированную аргументацию.
August 31 2012, 09:35:35 UTC 8 years ago
August 31 2012, 11:59:32 UTC 8 years ago
P.S. Кстати, а почему maven - абстрактный уровень над ant? Он вообще-то никак с ant не связан...
Maven, ответ на пост
September 7 2012, 09:44:32 UTC 8 years ago
September 27 2012, 08:20:54 UTC 8 years ago
Единственный момент, создается ощущение, что статья написана под влиянием какого-то спора. Причем всего спора целиком мы не видим, а только ответ автора, на какие-то аргументы оппонентов.
С удовольствием бы почитал сравнительную статью ant и maven с разворачиванием слабых мест обоих инструментов и как эти слабые места обходить.
Ну и плюс есть у меня обратные примеры: переписал как-то в Deutsche Bank систему сборки у одного тоже весьма нестандартного проекта с ant на maven - время сократилось с 40 минут до 3-5 минут.
То есть тут нужно внимательно смотреть на проект и думать. Уважаю и ант, и мавен, заодно присматриваюсь к gradle и bildr.
Ну а в целом достойный ответ бездумному продвиганию мавена.
September 27 2012, 11:26:49 UTC 8 years ago
8 years ago
8 years ago
November 13 2013, 19:55:29 UTC 7 years ago