Pull to refresh

Почему Gradle?

Reading time 7 min
Views 103K
Original author: Steve Ebersole
Если вы еще не знаете, что такое Gradle, то о нём можно почитать в предыдущих двух обзорах:
  1. Gradle: Better Way To Build
  2. Gradle: Tasks Are Code

Не так давно c Maven на Gradle была переведена сборка Hibernate Core. На что информационное сообщество отреагировало неоднозначно. Я хочу представить вашему вниманию перевод статьи, посвященной миграции сборки Hibernate. В статье раскрываются причины принятия такого решения, описываются преимущества Gradle и проблемы с Maven2. Дальнейшее повествование ведётся от лица Steve Ebersole.

Почему Gradle?


Многие просили меня записать причины, по которым я хочу перенести сборку Hibernate c Maven на Gradle, и здесь я их перечислю. Если вы впервые сталкиваетесь с Gradle, есть смысл просмотреть обзор. Прежде всего, хочу подчеркнуть, что цель этой статьи не «бей – круши — Maven» и не прямое сравнение Gradle с Maven. Это просто способ поведать миру о проблемах и разочарованиях, с которыми я столкнулся за 2.5+ года использования Maven для сборки Hiberbnate. Во многих случаях причина в несоответствии соглашений, используемых в Maven, тому, как я представляю себе сборку Hibernate. Некоторые пункты списка, собранного Полом, актуальны только для Hibernate (на этот список тоже стоит взглянуть). Так же это способ объяснить, почему я предпочел Gradle другим новым инструментам сборки (Buildr, SBT, и т.д.). Кстати, есть еще wiki сравнение Gradle и Maven, но оно изрядно устарело во многих частях. Особенно в том, что касается Gradle.

Вот проблемы (скорее в хронологическом порядке, чем «по важности»), с которыми я столкнулся в Maven:
  1. Maven не поддерживает многомодульные сборки. Утверждается, что поддерживает, но это не совсем точно. Если быть точным, он поддерживает сбоку группы независимых проектов. В чем разница? Для примера, возьмем Hibernate. У нас есть набор модулей, которые мы собираем. Модули существуют исключительно с целью разделения зависимостей соответственно используемым функциям. Не используете ehcache для кэширования? Без проблем, не используйте hibernate-ehcache модуль и ehcache не окажется в ваших зависимостях. Мы не собираемся никогда раздельно поставлять эти модули. Тогда зачем нам нужно задавать версию проекта снова и снова (во всех модулях)? Вот пример того, как maven усложняет простое. А последствия ощущаются когда, к примеру, я хочу сделать релиз. Я должен вручную убедиться, что версии совпадают во множестве разных мест (и даже не начинайте про release plugin)
  2. Ну ладно, раз начал про release plugin. Он вообще бесполезен. Я мог заставить его более-менее прилично работать на небольших проектах, но с Hibernate он практически всегда «падал». Хуже того, приходится ждать по 30-40-60 минут, чтобы узнать, что он не сработает, потом исправлять то, что ему не понравилось (если удалось это выяснить), и запускать по новой. В конце концов, мы просто сдались. (Кстати, друг только что заметил, что Jason van Zyl, низверг release plugin в седьмой круг ада, и что он будет заменен на «что-то новенькое»)
  3. Hibernate-core — основной артефакт. Hibernate-Annotations зависит от него. Maven об этом знает. Ну и почему тогда я не могу просто зайти в каталог hibernate-annotations и запустить 'maven compile', чтобы hibernate-core автоматически собрался тоже? (подсказка: см. п. 1) В любом случае: `cd hibernate-core; mvn install; cd ../hibernate-annotations; mvn compile`- ни в какие ворота не лезет. Инстумент сборки должен сам это понимать, после того как я преодолел столько препятствий, объясняя ему природу этих зависимостей.
  4. Один артефакт на проект. Я знаю, что это хорошее правило. Но Хорошие Правила редко бывают Абсолютными Истинами. И к примеру это ограничение Maven вынудило нас вынести тесты для hibernate-core за пределы hibernate-core. Потому что нам был нужен hibernate-testing, который зависит от hibernate-core и задает общую среду исполнения тестов и используется в большинстве других модулей (так же, мы хотели сделать его доступным для пользователей). И теперь у нас постоянно происходят коммиты, ломающие тесты, потому, что разработчики (включая и меня) забывают запустить тесты из-за того, что они лежат в каком-то другом, совершенно отдельном модуле. Да, в основном это проблема внимания к деталям, но разве не в решении таких вопросов должен помогать инструмент сборки вместо того, чтобы их создавать? Ну и один каталог исходников и один каталог скомпилированных классов на проект. См. http//in.relation.to/Bloggers/SimultaneouslySupportingJDBC3AndJDBC4WithMaven
  5. Я, лично, терпеть не могу концепцию объединения «inherited pom data» и «module aggregation» в одном файле. Это ужасная мысль. Многие maven разработчики согласны со мной и помогли разработать схему, при которой Hibernate разносит «inherited pom data» в ./parent/pom.xml, а «module aggregation» в ./pom.xml. Отлично, maven это поддерживает… ну почти отлично: он почти поддерживает. Проблема в том, что многие plugin'ы это не поддерживают, и начинаются мелкие, заковыристые проблемы. Зачем тогда вообще разносить? Как я уже сказал, я не считаю объединение правильным. Но почему бы не переступить через «правильно» и не сделать по-другому, т.к. Maven работает по-другому? Проблема в настройках после первоначального checkout. Вы не можете собрать модуль, пока нет его родителя. Но если родитель — агрегатор, то единственный способ собрать модуль — установить весь проект (или знать ключи команд maven и отключить рекурсию)
  6. В самом начале, 2.5 года назад, мне пришлось столкнуться с нашей сборкой DocBook. Кристиан своей работой над сборкой DocBook с использованием Ant в Hibernate задал планку для многих open-source Java проектов. У меня были мысли, как это улучшить, используя концепцию управления зависимостями для скачивания нужных компонент по мере необходимости. Проблема в том, что для того, чтобы сделать что-либо похожее в Maven вам придется написать plugin. Нельзя «просто накидать скрипт, а потом, если он окажется полезным, я упакую его для других» (Я понимаю, что сейчас это в некоторой степени возможно при помощи GMaven и т.д., но тогда это было не так). Так что пришлось писать jDocBook plugin и еще несколько. И со всеми ними были проблемы. Это единственный раз, когда я прямо сравню Gradle и Maven, потому что Gradle «попал в яблочко». Писать plugin'ы в Gradle (я написал уже 2 довольно крупных) очень приятно. В некотором смысле, это непросто из-за отсутствия инструкций о том, как это делать правильно, но API и возможности, которые предоставлены, просто восхитительны (да и не то, чтобы у Maven была документация по «правильным plugin'ам»).
  7. Многие пользователи хотели бы, чтобы скрипты сборки были настроены на взаимодействие с JBoss maven репозиторием. Вполне логично: сборка должна работать «из коробки». Но в Maven так сделать нельзя потому, что pom файл, используемый для сборки, будет использован и для установки в репозиторий. А большинство репозиториев (в том числе JBoss и Maven Central) проверяют, что pom-файлы не содержат настроек репозитория. Так что, вместо настройки скриптов, нам приходится поддерживать wiki и docbook и отсылать пользователей к документации.
  8. Запуск тестов Hibernate поверх нескольких баз данных практически невозможен через IDE, в IntelliJ как минимум с использованием интеграции. Проблема в профилях и том, как интеграция взаимодействует с ними (в плане фильтрации ресурсов)


Итак, пришло время начать поиски лучшего способа сборки Hibernate. Да, на горизонте маячил Maven3. Да, он добавляет некоторую «поддержку скриптов», но это скорее «рюшечка». Насколько мне известно, она просто позволяет по-другому настраивать все тоже самое. Поэтому я начал изучать Gradle среди прочих «DSL, build-by-convention» инструментов. (Кстати, «рюшечка» эта называется Polyglot Maven и, по словам друга, Jason van Zyl заявил, что она будет убрана и заменена на «что-то еще»).

  1. Первым и главным преимуществом стала возможность создавать скрипты для тех частей сбоки, которые слишком сложно описать в терминах «build by convention». Эта смесь мне понравилась: в вашем распоряжении лучшее от обоих миров.
  2. Столкнувшись с трудностями с доступом к информации из других модулей при сборке [с использованием Maven2 — прим. пер.], я понял, что возможность написать перебор модулей сборки с использованием замыканий во многих случаях просто «дар Божий». Так же как и способ настроить стандартные параметры для всех подпроектов в главном скрипте gradle — шедевр, намного превосходящий концепцию наследования в Maven.
  3. Общая гибкость в настройках сборки и каталогов так, как нужно мне, без необходимости следовать ограничениям системы сборки — это прекрасно
  4. Вся концепция процесса сборки в Gradle намного чище, imho. В Gradle можно не только задавать зависимости между модулями, но и невероятно гибко описывать зависимости от задач, модулей, каталогов и т.д. Например, в Gradle уже можно сказать, что один модуль зависит от скомпилированных классов, а не от результата (jar) сборки другого. Задумайтесь над этим. Очень и очень гибко. И полезно!
  5. У каждого проекта или модуля может быть несколько «Source set». «Source set» задает набор каталогов с исходниками, набор целевых каталогов, каталогов с ресурсами, и т.п… С помощью этого, к примеру, можно сделать вариант параллельной поддержки и тестирования JDBC3/JDBC4 такой, как я хотел (см in.relation.to/Bloggers/SimultaneouslySupportingJDBC3AndJDBC4WithMaven)
  6. Не знаю, к чему это отнести, но так приятно думать «Как же я буду это делать?» вместо «Какие варианты достичь желаемого оставит мне система сборки?»
  7. Инкрементальная сборка — это прекрасно. Как это? Она понимает, когда что-то изменилось, а когда — нет, и когда части сборки нужны на самом деле. Это встроено в plugin'ы. Задача определяет ввод и вывод, а Gradle использует эту информацию, чтобы определить, нужно ли запустить задачу, т.к. ее ввод изменился, и обновила ли задача свой вывод и поэтому нужно запустить зависящие от нее задачи. В итоге, последующие сборки становятся очень быстрыми
  8. Способность Gradle публиковать артефакты в maven-репозитории и генерировать точные POM'ы не только уникальна, но была и важным аргументом принятия решения о переходе. У меня могут быть претензии к сборке Hibernate при помощи Maven, но возможность создавать и использовать артефакты унифицированным образом крайне необходима. В общем случае, Gradle способен сгенерировать POM по той информации, которой располагает. А если нет, вы можете просто описать дополнительные параметры в замыкании для настройки POM. Это к вопросу о гибкости.
  9. Генерация проектов IDE. Это был еще один важный аргумент. Большинство разработчиков Hibernate используют Eclipse или IntelliJ. Лично я провожу большую часть времени в IDE: пишу код, запускаю тесты, оформляю документацию. Я не собирался идти путём усложнения работы в IDE. Уже довольно давно Gradle может создавать проекты под Eclipse. Недавно появилась возможность генерировать проекты и под IntelliJ. Для нее, говорят, разрабатывается и интеграция gradle, аналогичная maven
Tags:
Hubs:
+1
Comments 7
Comments Comments 7

Articles