Почему Java не используется в качестве языка сборки?

24

Если Java является языком общего назначения, а сборка программы - это то, что можно описать с использованием языка Java, почему это не лучший способ написания файлов сборки, и вместо этого мы используем такие инструменты, как Ant, Maven и Gradle? Разве это не будет более простым, а также избавит от необходимости изучать еще один язык программирования? (Кстати - этот вопрос также может быть применен к другим языкам, например, C #)

vainolo
источник
7
У вас может быть немного более интересный вопрос о том, «почему языки общего назначения не используются для языков сборки» - я имею в виду, что C также не является языком сборки. Я бы также предложил посмотреть на церемонию компиляции одного файла .java на Java
8
Это, вероятно, можно обобщить как «Зачем беспокоиться о DSL?»
FrustratedWithFormsDesigner
1
Лучший вопрос может быть; почему IDE / компиляторы / инструменты настолько плохи, что инструменты сборки нужны в первую очередь.
Брендан,
6
@Brendan - это не вопрос, так как инструменты сборки и IDE служат для разных целей.
jwenting
1
Потому что языки «общего назначения» никогда не должны использоваться вместо четко определенных, простых предметно-ориентированных языков. И, если вас интересует необходимость изучения «еще одного языка программирования», вам не стоит заниматься программированием, попробуйте другой способ.
SK-logic

Ответы:

21

Специальный инструмент для конкретной цели

  • многословие

    Языки общего назначения часто слишком многословны. Если бы мне пришлось управлять сборкой на Java, я бы очень быстро впал в депрессию из-за размера зверя. Тем не менее, им можно легко управлять с помощью DSL, написанного на Java. И в некоторой степени именно так вы можете видеть Gradle (для Groovy) и Buildr (для Ruby).

  • трудность

    Языки общего назначения сложны. Ну, я не думаю, что программирование сложно и никто не может его понять, но дело в том, что ваш инженер по сборке не обязательно ваш программист!

  • Цель

    Это более или менее на пересечении сложности и многословия . Язык разработан для определенной цели, и здесь мы говорим о чем-то очень специфическом. Так зачем вам нужен язык общего назначения? Для сборки вам понадобится:

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

    Вам действительно не нужно намного больше.

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

Вероятно, поэтому существует полярность между людьми, которые предпочитают декларативные системы сборки большинству программируемых элементов: я полагаю, что у разработчика может быть естественная тенденция искать способы выхода из коробки.

Подождите, нам действительно нужен инструмент?

Еще один связанный с этим вопрос: нужен ли нам инструмент сборки? Разве тот факт, что они существуют на всех языках, не является признаком того, что они заполняют пробел, которого вообще не должно быть?

Некоторые языки не обязательно требуют инструмента сборки. Например, большинство языков сценариев не нуждаются в них и разрешаются во время загрузки. Или возьмем Go, чей компилятор будет обрабатывать все для вас, что является хорошим контрапунктом: что, если компилятору, подобному gcc, внезапно не понадобится куча флагов, компоновщик и make-файл, чтобы все умереть вместе? Или если javac не нужен build.xml или pom.xml, чтобы сказать ему, что делать? Разве управление зависимостями не должно быть частью собственного инструментария языка, так как зависимости являются частью окончательной программы?

Это, безусловно, кажется гораздо более простым подходом для пользователя (строителя). Хотя можно утверждать, что они просто скрываются и лишают вас выбора и возможностей влиять на этот процесс сборки (но тогда вы надеетесь, что такой инструмент позволяет использовать расширения компилятора и подобные вещи). Кроме того, мы привыкли рассматривать инструменты и язык как две разные вещи, поэтому он может показаться неуверенным, чтобы внезапно связать их так тесно.

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


Лично я использовал make / gmake / autotools / pmk и был доволен ими для C, и я начал с Java, когда все, что у нас было, это make, затем ant, и теперь я обычно предпочитаю Maven всем этим альтернативам. Хотя я вижу ценность в gradle, buildr и других, но мне нравится распространенность maven до тех пор, пока не произойдет более значительный сдвиг. Плюс мне нравится, что он жесткий, но все же оставляет вам возможность обойти это в случае необходимости. То, что это не легко, это хорошо.

Это инструмент для сборки. Просто научись принимать это и не борись с этим. Это проигрышная битва. Или, по крайней мере, очень, очень длинный.

haylem
источник
Очень нравится твой прагматизм. Мой вопрос из любопытства. Я использую maven (в прошлом использовал make и ant), и он делает «черную магию», которая иногда хороша, а иногда и плоха. Но это все еще волшебство.
Вайноло
1
«Или если javac не нужен build.xml или pom.xml, чтобы сказать ему, что делать?» Хех. это не так и никогда не делал.
user253751
@immibis: это спорно. Мне бы не очень понравилось создавать свои проекты в офисе только с использованием javac :). Конечно, для сборки всего этого потребовалось бы немножко клея с помощью либо Makefile, либо сценария оболочки, либо, по крайней мере, псевдонимов оболочки. Или гигантская программа со всем в одной папке и всеми депо в репо. Не совсем то, что я хотел бы! :) Но это совершенно другая дискуссия, не связанная с вопросом ОП.
Хайлем
Интеграция системы сборки с языком также проблематична для проектов полиглотов. Если я использую оба языка A и B и хочу иметь один процесс сборки для них, какую систему сборки языка я использую?
Себастьян Редл
@SebastianRedl Так, как проблема облегчается, вводя третий язык? Просто выберите язык, который работает лучше для вас. (И, конечно, если вам нужен третий язык, Java также может быть им.)
Ville
21

Javaявляется обязательным языком, Ant, Mavenи т.д., декларативные языки:

Мы могли бы определить разницу следующим образом:

  • Императивное программирование: рассказывать «машине», как что-то делать, и в результате произойдет то, что вы хотите.
  • Декларативное программирование: рассказать «машине» о том, что вы хотели бы случиться, и дать компьютеру понять, как это сделать. 1

Языки сборки сообщают сборщику, что следует делать, откуда его брать и т. Д. Механизм, который выполняет сборку (которая написана на императивном языке, как заметил @ElliottFrisch), читает эти инструкции и выполняет их.

Декларативные языки могут показаться более подходящими в сценариях сборки, поскольку задачи сборки, как правило, одинаковы во всем, и они считаются более удобными и читаемыми в этой форме, чем в полноценной форме кода.

Ури Агасси
источник
3
Есть хотя бы одна система сборки, которая использует императивный язык. Scons использует Python.
user16764
Сделать его обязательным не сложнее, чем написать класс, который может содержать список зависимостей, и метод для разрешения этих зависимостей. Я подозреваю, что есть и другая причина - например, время запуска JVM.
2
@Lee: Почти все инструменты сборки, используемые в мире Java (Ant, Maven, Gradle, SBT,…), также обычно работают на JVM (за исключением Rake, Buildr или Scons, которые могут , но не имеют для запуска на JVM).
Йорг Миттаг
6
@vainolo "Большинству людей не очень нравятся Ant / Maven / Make"? Это смелое заявление!
Бен Терли
1
@BenThurley Мне нравились люди, почему был создан муравей? а если муравей любил, то почему мавен? А теперь, почему люди используют Gradle? Но я согласен с тем, что это смелое утверждение, и оно подкреплено лишь «анекдотическими» свидетельствами нескольких десятков разработчиков Java
vainolo
4

Если вы посмотрите на особенности типичной системы сборки, вы обнаружите:

  1. Много данных: имена, переключатели, настройки, элементы конфигурации, строки и т. Д.
  2. Много взаимодействия с окружающей средой: команды, переменные среды
  3. Относительно простой «механизм сборки», обрабатывающий зависимости, потоки, ведение журнала и т. Д.

Если вы намереваетесь написать серию файлов сборки, используя некоторый язык (Java / C # / Python / и т. Д.), Примерно на третьей или четвертой итерации вы бы остановились на (а) сохранении большей части данных и внешних команд как данных в чем-то как XML (б) написание «движка сборки» на вашем любимом языке.

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

Другими словами, вы закончите с Make, или Ant, или Rake, или MsBuild. Императивный язык для того, что он делает хорошо, и структуры данных для описания того, что вы хотите сделать, теперь обычно в XML.

david.pfx
источник
2

В этих случаях против использования Java / C ++ / C # учитывается ряд факторов.

Во-первых, вам нужно скомпилировать сценарий сборки, прежде чем запускать его для сборки приложения. Как бы вы указали какие-либо пакеты, флаги, версии компилятора, пути к инструментам, необходимые для сборки вашего сценария сборки? Конечно, вы могли бы придумать способ обойти это, но гораздо проще иметь либо язык, который не нуждается в этом шаге сборки (например, python), либо язык, который ваш инструмент сборки понимает изначально.

Во-вторых, файлы сборки требуют больших объемов данных, тогда как Java / C ++ / C # гораздо больше ориентированы на написание кода и алгоритмов. Java и друзья не очень кратко представляют все данные, которые вы хотите сохранить.

В-третьих, Java и друзьям нужно много шаблонов, чтобы быть действительными. Файл компоновки должен находиться внутри метода внутри класса со всеми его импортами. При использовании языка сценариев или пользовательского языка вы можете избежать всего этого и просто иметь подробности сборки.

Уинстон Эверт
источник
0

Верно! Почему бы не использовать мощный и выразительный язык для более сложной проблемы, чем думают люди (изначально)? Особенно, когда люди, сталкивающиеся с проблемой, уже владеют таким языком. (Сборка - это собственная проблема программистов, которую лучше всего решать программистам.)

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

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : В этом ответе я продвигаю iwant , систему сборки, которую разрабатываю. Но так как это в любом случае самоуверенное обсуждение, я уверен, что все в порядке.

Я не буду подробно останавливаться на преимуществах Java (мощь и выразительность) или на iwant. Если вы заинтересованы, вы можете прочитать больше на странице iwant .

Вместо этого я рассмотрю, почему Java (и другие GPL) так легко отклоняются как непригодные для сборки. Многие ответы и комментарии здесь являются хорошими примерами такого мышления. Давайте рассмотрим некоторые типичные аргументы:

«Java обязательна, но сборки лучше всего определять декларативным способом» , - говорят они.

Правда. Но при использовании языка в качестве метаязыка для внутреннего DSL на самом деле важен его синтаксис . Даже такой императивный язык, как Java, может быть обманут, чтобы быть декларативным. Если это выглядит и кажется декларативным, это (для практических целей) декларативно. Например:

JacocoTargetsOfJavaModules.with()
    .jacocoWithDeps(jacoco(), modules.asmAll.mainArtifact())
    .antJars(TestedIwantDependencies.antJar(),
            TestedIwantDependencies.antLauncherJar())
    .modules(interestingModules).end().jacocoReport(name)

Это реальный пример из демонстрационного проекта iwant .

Фактически, сравните это с некоторыми якобы декларативными системами сборки, которые предоставляют своим пользователям такие обязательные глаголы, как «test» или «compile». Вышеуказанная декларация содержит только существительные, без глаголов. Компиляция и тестирование - это задачи, неявно выполняемые iwant для предоставления пользователю существительных, которые он / она хочет. Это не язык. Это то, как вы используете это.

"Ява многословна"

Да, много Java-кода там многословно. Но опять же, это не язык, а то, как вы его используете. Если реализация многословна, просто заключите ее в красивую абстракцию. Многие GPL предоставляют адекватные механизмы для этого.

Просто представьте приведенный выше фрагмент кода Java, написанный на XML. Замените скобки угловыми скобками и переместите их. А затем продублируйте каждое ключевое слово как закрывающий тег! Java , как синтаксис является не многословен.

(Я знаю, что сравнивать с XML - это все равно, что отнимать конфеты у ребенка, но так много сборок просто определено в XML.)

«Вы должны скомпилировать свой скрипт сборки»

Это верный момент. Тем не менее, это просто небольшая техническая проблема, которую нужно решить. Я мог бы решить это с помощью бобов или другого интерпретатора. Вместо этого я решил эту проблему, рассматривая ее как еще одну проблему сборки и загружая iwant с помощью простого сценария оболочки или муравья, который компилирует и запускает простой загрузчик Java.

"Ява имеет образец"

Правда. Вы должны импортировать классы, вы должны упомянуть «public», «class» и так далее. А вот простые внешние DSL дают начальный легкий выигрыш.

И если ваш проект настолько тривиален, что этот шаблон является значительным, поздравляю. Ваша проблема не сложная, и на самом деле не имеет значения, как вы ее решаете.

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

Вилле Оикаринен
источник
0

Одна вещь, которую я не думаю, что другие ответы были адресованы, - то, что ограничения и прозрачность этих языков сборки - огромная часть того, что делает их полезными. Давайте возьмем Maven, например. Да, он выполняет сборку, но также определяет зависимости. Это позволяет сборке Maven удалять эти зависимости и просматривать их зависимости и так далее, и так далее.

Подумайте, было ли это сделано непосредственно с Java. Инструмент сборки будет видеть, что есть зависимость. Затем ему нужно было бы свернуть другое Java-приложение и выполнить его, чтобы определить его зависимости. Но для Maven он просто смотрит на объявления зависимостей. Файл сборки maven прозрачен. Полный язык Тьюринга по своей природе непрозрачен и поэтому уступает некоторым целям, таким как этот.

JimmyJames
источник
Как Gradle вписывается в это? Он определяет зависимости в декларативном стиле, используя язык общего назначения (Groovy). В инструментах на основе Groovy, JavaScript или Lisp естественно использовать компилятор или интерпретатор языка для разбора объявлений, хотите ли вы просто прочитать их или «выполнить» (примените некоторую функцию). Эта двойственность кода и данных не является частью общепринятой идиомы Java, хотя и не невозможна. Полнота Тьюринга не мешает хорошему представлению данных. Это открывает возможность того, что ваши данные будут делать то, чего вы не ожидали.
Joshp
@joshp Я не знаком с Gradle. Это описывается как DSL, и все выглядит довольно декларативно. Быть основанным на Groovy не обязательно означает, что он эквивалентен Groovy по своей мощи. Вы, вероятно, были бы в лучшем положении, чтобы сказать, является ли Gradle фактически полным по Тьюрингу языком. Примеры зависимости, на которые я смотрел, кажутся довольно простыми. Можете ли вы использовать произвольные выражения Groovy в таких вещах, как объявления зависимостей?
JimmyJames
Лично мне даже не нравятся переходные зависимости. Часто они просто вызывают сюрпризы в пути к классам (несколько несовместимых версий библиотек). Вот почему у maven есть элемент exclude, но хлопоты не просто стоят того. Явные зависимости делают жизнь проще. Тем не менее, транзитивные зависимости могут быть реализованы с помощью Java. Я сделал что-то подобное с iwant , повторно используя определения сборки других проектов.
Вилле
@ VilleOikarinen Я в основном согласен с тобой. Я думаю, что это также вызывает кучу раздувания, поскольку нет никакой очевидной платы за увеличение числа зависимостей, даже если вы их не используете. Тем не менее, в контексте этого ответа я не комментирую ценность или мудрость этой функции, а то, как использование DSL полезно для ее достижения.
JimmyJames
1
@VilleOikarinen Я думаю, мы достигли конца этого, но я просто хочу уточнить, что я не говорю о pom / maven. Это пример сборки DSL, но я не думаю об этом. Я использую это неохотно, и я думаю, что это неуклюже. Но что является доминантой, так это декларации зависимости. Я использовал Buildr некоторое время, и он читает pom для зависимостей, но он не использует их для спецификаций сборки. Существует ряд инструментов, не основанных на Java, которые понимают этот pom, но AFAIK, все, что их волнует, это зависимости.
JimmyJames