Написать, наконец, этот пост меня заставила уже давняя дискуссия вот к этому посту на тему, которая время от времени всплывает то там, то тут.

Я много раз имел возможность убедиться, что далеко не все одинаково понимают, в чем же состоит декларативность vs процедурность той или иной системы сборки. Основным достоинством инструмента сборки зачастую считается возможность писать алгоритмы сборки на удобном языке. Нужен DSL, никуда без него.

В gradle этот DSL базируется на groovy. sbt использует скалу, leiningen — Clojure, Ant использует xml (совершенно не по делу, кстати). Несложно припомнить системы сборки на базе javascript. Каждый собирает на том языке, который ему ближе. И новые инструменты пишут, например, на котлине.

Увы, но наличие DSL совсем не означает декларативности. Скорее наоборот. В итоге, gradle проект вообще не может полноценно жить без pom.xml. Это шутка, но с большой долей правды. Посмотрите вот сюда: это репозиторий.

Что у нас тут лежит? Да-да, именно pom.xml, он самый. А где же у нас build.gradle? А нет его. Понимаете? Его тут нет.

То есть все метаданные, которые предоставлены о собранном проекте, который заметим, собирается при помощи gradle, состоят только и исключительно из метаданных maven.

Вас это не удивляет? Меня — нисколько. На мой взгляд, gradle, sbt, leiningen и многие другие инструменты почти (или вовсе) не предоставляют метаданных в доступном другим продуктам виде.

Они реально видны только самим себе, и только изнутри процесса сборки. Просто потому, что скрипт сборки — это груви код (Clojure, скала, javascript). Именно поэтому же их так плохо поддерживают IDE (в сравнении с maven или ant, где скрипт это xml). Чтобы понять, что там происходит, нужно выполнить. Нужно иметь gradle внутри, и нужно чтобы gradle отдавал в IDE необходимую информацию.

Как я вижу себе декларативность, и зачем она бывает нужна? В качестве иллюстрации приведу два своих проекта, и один от apache:

  • Начнем пожалуй с Apache Karaf. В ssh-консоли вам доступна команда установки модуля (OSGI-bundle). Эта команда использует не что иное, как координаты модуля в maven repository: bundle:install mvn:groupId/artifactId/version. При этом самого maven karaf не содержит — под капотом ничто иное, как Aether, плюс обертка над ним (Pax URL).
  • Аналогичную конструкцию я реализовал когда-то давно на Jython, и работала она внутри Weblogic. Использовался тот же Aether, плюс WLST API. И позволяло все это автоматически обновлять установленные в контейнере JavaEE модули, разыскивая их новые версии в репозитории.
    Опять же — maven в конструкцию не входил. Использовались репозиторий, Aether, и pom.xml, которые maven упаковывает в META-INF модуля.
  • И последний пример. В моей практике был один maven plugin, который в качестве исходных данных для своей работы использовал SVN, сканируя папки и файлы на предмет изменений в проектах, сравнивая их с bug tracker, и принимая решения, какие именно собранные артифакты нужно включать в релиз, и деплоить.

Какие выводы можно из этого сделать?

Во-первых, мы видим, что с описанием проекта (в моем случае это всегда был pom.xml) иногда бывает нужно и можно работать из любого достаточно развитого языка. Это не обязан быть инструмент сборки, на который изначально расчитан проект.

Во-вторых, если репозиторий спроектирован правильно, в соответствии с принципами REST, то нам не нужен никакой специальный софт для работы с ним, кроме http-сервера. Нужны только данные метауровня чуть выше проекта (список доступных версий, например).

В-третьих, очень удобно то, что важная часть инфраструктуры, в нашем случае plugins, сами просто обычные артефакты, лежат в том же репозитории, и никак не связаны вообще с конкретным проектом.

Вот это я называю декларативным подходом. У нас есть проекты, их много. Они бывают в репозитории, в виде собранных артефактов, в VCS, и еще где-либо, и могут обрабатываться разными инструментами — а не только одним единственным. Дескриптор проекта — это просто файл, любого стандартного и удобного для обработки формата. Репозиторий артефактов — это тоже стандартизованный формат + простой REST API. А логика сборки, на любом удобном вам DSL, лежит отдельно. Хотите — в самом дескрипторе, хотите — в репозитории.

Как бы я вообще это все сделал? В сущности, если брать за основу maven, то сейчас тут не хватает гибкости в части plugins, их настроек, и т.п., потому что существующий xml — это сериализованное представление java-модели данных plugins и ядра, и оно не гибко. Если разработчики решили, что какие-то данные о проекте вам не нужны — у вас остается только вариант key-value в виде properties.

А следовало бы сделать нечто произвольной, но регулярной структуры, ну скажем типа RDF (не обязательно именно его).
Описание проекта в виде RDF сразу позволяет делать полезные вещи вроде поиска в нем, как в базе данных (т.е. репозиторий, в части метаданных, становится просто SPARQL endpoint, и умеет отвечать на поисковые запросы). И такие же запросы можно строить применительно к проекту.

Вот это и был бы истинный poliglot maven. Причем это, кстати, выглядит вполне реализуемо, даже в рамках существующей инфраструктуры.
Поделиться с друзьями
-->

Комментарии (3)


  1. DarkOrion
    20.06.2016 16:12
    +3

    Мне кажется maven сейчас лучшее, что у нас есть. Самый большой его напряг описан в статье habrahabr.ru/company/jugru/blog/191246 и это стратегия nearest. Минусы мавена — плохая документация, которая описывается примерно 10% его функциональности и частично устарела\врет. Тот случай когда регулярно надо смотреть в код реализации плагина, либо в готовый конфиг. Я иногда хожу по гитхабу, смотрю чужие pom-ы, «а что, так можно было?» — почти в каждом проекте.


    1. sshikov
      20.06.2016 17:00

      Минусы мавена — плохая документация, которая описывается примерно 10% его функциональности и частично устарела\врет.


      Вы книжку от Sonatype читали? В смысле, обе книжки?


  1. vstartsev
    21.06.2016 23:02

    А вот это вот не ожидал. В Maven зависимости, а в Gradle логика сборки — удобно. Вы поправили мою вселенную сборки проектов.