Написать, наконец, этот пост меня заставила уже давняя дискуссия вот к этому посту на тему, которая время от времени всплывает то там, то тут.
Я много раз имел возможность убедиться, что далеко не все одинаково понимают, в чем же состоит декларативность 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. Причем это, кстати, выглядит вполне реализуемо, даже в рамках существующей инфраструктуры.
Автор: sshikov