为什么不将Java用作构建语言?


24

如果Java是一种通用语言,而构建程序可以用Java语言来描述,那么为什么这不是编写构建文件的最佳方法,而是使用Ant,Maven和Gradle之类的工具呢?那不是更直接,而且不需要学习另一种编程语言吗?(顺便说一句-这个问题也可以应用于其他语言,例如C#)


7
关于“为什么不是通用语言用于构建语言”的问题,您可能会更感兴趣-我的意思是,C也不是一种构建语言。我还建议您查看有关在Java中编译单个.java文件

8
这可能可以概括为“为什么要打扰DSL?”
FrustratedWithFormsDesigner 2014年

1
一个更好的问题可能是;为什么IDE /编译器/工具如此糟糕,以至于首先需要构建工具。
布伦丹2014年

6
@Brendan毫无疑问,因为构建工具和IDE具有不同的用途。
jwenting 2014年

1
因为永远不要使用“通用”语言来代替定义明确的,简单的领域特定语言。而且,如果您需要学习“另一种编程语言”,那您就不应该真正地进行编程,可以尝试其他一些方法。
SK-logic

Answers:


21

专用工具

  • 细度

    通用语言通常太冗长。如果我必须用Java管理构建,那么野兽的大小会让我非常沮丧。但是,使用Java编写的DSL可以很容易地对其进行管理。在某种程度上,这就是您可以看到Gradle(对于Groovy)和Buildr(对于Ruby)的方法。

  • 困难

    通用语言很难。好吧,我认为编程并不困难,任何人都不会接受,但是重点是:您的构建工程师不一定是您的程序员!

  • 目的

    这或多或少是困难冗长的交集。语言是为特定目的而设计的,在这里我们谈论的是非常具体的东西。那么,为什么你需要或想要使用一般用途的语言?对于构建,您需要:

    • 分支和条件来处理单独的配置,环境等...
    • 一组指示信息,用于从您的环境中提取数据,
    • 一套生产成果的说明。

    您实际上并不需要更多。

当您的构建系统对于您要使用的一种特殊用例而言似乎不够灵活时,肯定会很烦人,但对于大多数人而言,它可能比替代用例好得多。

这就是为什么在使用声明式构建系统而不是大多数可编程一次的人之间存在两极分化的原因:我猜开发人员可能会自然而然地寻求突破性的方法。

等等,我们真的需要工具吗?

另一个相关的问题是:我们真的需要构建工具吗?它们是否存在于所有语言中,这不是事实,它们填补了最初不应该存在的空白的迹象吗?

某些语言不一定需要构建工具。例如,大多数脚本语言不需要一种,并且可以在加载时解析。或采用Go,后者的编译器将为您处理所有事情,这是一个很好的对策:如果像gcc这样的编译器突然不需要一堆标志,链接器和makefile来使所有内容都消失了怎么办?或者,如果javac不需要build.xml或pom.xml来告诉他该怎么办?依赖关系管理不应该是语言本身工具的一部分,因为依赖关系是最终程序的一部分吗?

对于用户(构建者)来说,这无疑似乎是一种更为简单的方法。尽管可能会说他们只是在幕后进行,并且剥夺了您的选择和机会来影响构建过程(但是您希望这样的工具可以允许编译器扩展和类似的东西)。另外,我们过去常常将工具和语言看作是两个独立的事物,因此他突然将它们如此紧密地结合在一起似乎并不纯洁。

我认为您用于构建程序的语言不是问题。重要的是您用于编程的语言,其核心平台和工具,而我们在此方面仍在取得进展。


就个人而言,我使用过make / gmake / autotools / pmk并为C感到满意,我从Java开始,那时我们只有make,然后是ant,现在我通常更喜欢Maven,而不是所有其他选择。尽管我可以在gradle,builder和其他工具中看到价值,但是到目前为止,我喜欢maven的盛行,直到发生更重要的转变为止。另外,我喜欢它很严格,但是如果需要的话,仍然使您无法解决它。这不容易是一件好事。

这是一个构建工具。只要学会拥抱它,就不要与它抗争。这是一场失败的战斗。或至少非常长的一个。


真的很喜欢你的实用主义。我的问题是出于好奇。我使用Maven(过去曾使用过make和ant),它确实起到了“黑魔法”的作用,有时是好是坏。但这仍然是魔术。
vainolo 2014年

1
“或者,如果javac不需要build.xml或pom.xml来告诉他该怎么做?” -嘿。它没有,也从未如此。
user253751

@immibis:这值得商bat。我不太喜欢只使用javac在办公室构建项目:)当然,要使用Makefile或Shell脚本或至少使用shell别名将东西放在一起,这肯定需要很多胶水。或者是一个巨大的程序,其中所有内容都放在一个文件夹中,而所有部门都在仓库中。并不是我想要的东西!:)但这完全是另一场辩论,与OP的问题无关。
haylem 2015年

对于多语言项目,将构建系统与语言集成也是有问题的。如果我同时使用语言A和B,并希望有一个单一的构建过程,那么我将使用哪种语言的构建系统?
塞巴斯蒂安·雷德尔

@SebastianRedl那么,通过引入第三种语言如何使问题变得更容易?选择适合自己的语言。(当然,如果您需要第三语言,Java也可以。)
Ville Oikarinen

21

Java是一种必要的语言AntMaven等等都是陈述性的语言:

我们可以将差异定义如下:

  • 命令式编程:告诉“机器” 如何做某事,结果您想发生的事情就会发生。
  • 声明式编程:说的是“机” 有什么你想发生,并让计算机计算出如何做到这一点。1个

构建语言告诉建设者什么应该做的,从那里应该采取等的引擎,它运行的版本(这是写在命令式语言,像@ElliottFrisch注意到),阅读这些说明,并满足他们。

在构建场景中,声明性语言似乎更合适,因为构建任务通常在整个过程中都是相同的,并且与正式的代码形式相比,以这种形式被认为更具可维护性和可读性。


3
但是至少有一个使用命令式语言的构建系统。Scons使用Python。
user16764 2014年

但是,使之变得势在必行的事情就是编写一个可以包含依赖项列表的类,以及解决这些依赖项的方法。我怀疑还有另一个原因,例如JVM启动时间。

2
@Lee:Java世界中使用的几乎所有构建工具(Ant,Maven,Gradle,SBT等)通常也都在JVM上运行(Rake,Buildr或Scons除外,它们可以但不具有在JVM 运行)。
约尔格W¯¯米塔格

6
@vainolo“大多数人真的不喜欢Ant / Maven / Make”吗?那是一个大胆的声明!
Ben Thurley 2014年

1
我喜欢的@BenThurley我为什么要造蚂蚁?如果喜欢蚂蚁,为什么是行家?现在人们为什么要使用Gradle?但是我同意这是一个大胆的声明,并且只有数十名Java开发人员的“轶事”证据作为支持
vainolo 2014年

4

如果查看典型构建系统的功能,则会发现:

  1. 大量数据:名称,开关,设置,配置项,字符串等
  2. 与环境的大量交互:命令,环境变量
  3. 相对简单的“构建引擎”,用于处理依赖项,线程,日志记录等。

如果您打算使用某种语言(Java / C#/ Python / etc)编写一系列构建文件,那么大约在第三或第四次迭代之前,您就可以(a)将大多数数据和外部命令作为数据保留在某些东西中例如XML(b)用您喜欢的语言编写“构建引擎”。

您还会发现将XML中的某些数据视为一种解释语言,以触发构建引擎中的各种功能很有用。您还可以在数据中解释一些宏或执行字符串替换。

换句话说,您将完成Make,Ant,Rake或MsBuild。现在,一种常用的命令式语言通常以XML表示其性能良好,并使用数据结构来描述您要执行的操作。


2

在这些情况下,有许多因素不利于使用Java / C ++ / C#。

首先,您必须先编译构建脚本,然后才能运行它来构建应用程序。您将如何指定构建构建脚本所需的任何软件包,标志,编译器版本,工具路径?当然,您可以想出一种解决方法,但是拥有一种不需要该构建步骤的语言(例如python)或您的构建工具本身可以理解的语言则要简单得多。

其次,构建文件的数据量很大,而Java / C ++ / C#更适合编写代码和算法。Java和朋友对您要存储的所有数据没有非常简洁的表示。

第三,Java和朋友们需要大量的样板才能有效。构建文件必须位于包含所有其导入的类中的方法内部。使用脚本语言或自定义语言时,您可以避免所有样板操作,而自己拥有构建详细信息。


0

确实!为什么不使用功能强大富有表现力的产品语言来解决比人们通常(最初)想的还要复杂的问题?尤其是面对问题的人已经可以使用这种语言。(构建是程序员自己的问题,最好由程序员解决。)

几年前,我也问自己这个问题,并决定Java是定义内部版本的好语言,尤其是对于Java项目。结果,我开始对此做一些事情。

免责声明:在这个答案中,我正在推广iwant,这是我正在开发的构建系统。但这毕竟是一个经过深思熟虑的讨论,因此我确定是可以的。

我不会详细说明Java的好处(功能和表现力),也不会特别介绍。如果您有兴趣,可以在iwant页面上阅读更多内容

相反,我将考虑为什么Java(以及其他GPL)如此容易被驳回为不适合构建。这里的许多答案和评论都是这种思考的很好例子。让我们考虑一些典型的参数:

他们可能会说:“ Java是必须的,但最好以声明性的方式定义构建。”

真正。但是,当使用一种语言作为内部DSL的主要语言时,真正重要的是其语法。甚至像Java这样的命令性语言也可以被欺骗为声明性的。如果看起来和感觉上是声明性的,则(出于实际目的)是声明性的。例如:

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

这是来自iwant演示项目的真实示例。

实际上,将其与一些假定的声明性构建系统进行比较,该构建系统会将其用户暴露于“测试”或“编译”等命令性动词。上面的声明仅包含名词,不包含动词。编译和测试是iwant隐式处理的任务,目的是向用户授予他/她想要的名词。这不是语言。这就是您的使用方式。

“ Java很冗长”

是的,很多Java代码都很冗长。但是,这又不是语言,而是您的使用方式。如果实现是冗长的,只需将其封装在漂亮的抽象后面即可。许多GPL为此提供了足够的机制。

试想一下上面用XML编写的Java代码段。用尖括号代替括号,然后将其移动。然后将每个关键字复制为结束标记!Java作为一种语法不是冗长。

(我知道,与XML进行比较就像从婴儿身上拿糖果一样,但是很多构建恰好是用XML定义的。)

“您必须编译您的构建脚本”

这是有道理的。尽管如此,这只是一个需要解决的小技术问题。我可以通过使用beanshell或其他解释器解决它。相反,我通过将其视为另一个构建问题并使用编译和运行简单Java引导程序的简单shell或ant脚本进行引导来解决它。

“ Java有样板”

真正。您必须导入类,必须提及“ public”,“ class”等。简单的外部DSL在这里赢得了最初的轻松胜利。

如果您的项目如此琐碎,以至于这个样板很重要,那么恭喜您。您的问题并不难,而且解决的方式也无关紧要。

但是许多项目所需要的不仅仅是编译,覆盖报告和打包。如果Java样板可以解决客户的问题,那么为什么不构建问题呢?为什么只为别人的孩子做鞋?


0

我认为没有其他答案可以解决的一件事是,这些构建语言的局限性和透明性是使它们有用的很大一部分。让我们以Maven为例。是的,它执行构建,但它也定义了依赖关系。这使得Maven构建可以下拉那些依赖项并查看它们的依赖项,依此类推。

考虑一下这是否直接用Java完成。构建工具将看到存在依赖性。然后,需要拉下其他Java应用程序并执行它,以确定其依赖项是什么。但是对于Maven,它只是查看依赖项声明。Maven构建文件是透明的。一种图灵完整的语言本质上是非透明的,因此在某些目的(例如该目的)方面不如后者。


Gradle如何适应呢?它使用通用语言(Groovy)以声明性样式定义依赖项。在基于Groovy,JavaScript或Lisp的工具中,很自然地使用语言的编译器或解释器来解析声明,无论您是要读取声明还是“执行”它们(应用某些函数)。尽管并非不可能,但代码和数据的双重性并不是公认的Java习惯用法的一部分。图灵完整性不会妨碍良好的数据表示。它确实打开了您的数据将执行您未曾期望的事情的可能性。
joshp

@joshp我对Gradle不熟悉。它被描述为DSL,并且看起来很声明。基于Groovy并不一定意味着它的功能与Groovy等效。如果Gradle实际上是图灵完备的语言,您可能会更合适。我看过的依赖示例似乎很简单。您可以在依赖项声明之类的东西中使用任意Groovy表达式吗?
JimmyJames

我个人甚至都不喜欢传递依赖。通常,它们只会在类路径(库的多个不兼容版本)中引起意外。这就是为什么Maven具有exclude元素的原因,但是麻烦并不仅仅值得。明确的依赖关系使生活更简单。仍然可以使用Java实现传递依赖。我做了类似的东西与iwant通过重复使用其他项目的生成定义。
Ville Oikarinen

@VilleOikarinen我恰好同意你的看法。我认为这也会引起大量的膨胀,因为即使您不使用依赖也没有成本。但是,在这个答案的背景下,我不是在评论该功能的价值或智慧,而是在使用DSL在实现此功能方面如何有用。
JimmyJames

1
@VilleOikarinen我认为我们已经结束了这一步,但我只是想澄清一下,我不是在谈论pom / maven。这是构建DSL的示例,但我认为它不多。我很笨拙地使用它,我认为它很笨重。但是pom如此占主导地位的是依赖项声明。我使用Buildr已有一段时间,它读取pom的依赖关系,但没有将它们用于构建规范。有许多不是基于Java的工具可以理解此pom,但可以理解AFAIK,它们所关心的只是依赖项。
JimmyJames
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.