Pourquoi Java n'est-il pas utilisé comme langage de construction?

24

Si Java est un langage à usage général et que la construction d'un programme peut être décrite en utilisant le langage Java, pourquoi n'est-ce pas la meilleure façon d'écrire des fichiers de construction et à la place nous utilisons des outils comme Ant, Maven et Gradle? Cela ne serait-il pas plus simple et supprimerait-il également la nécessité d'apprendre un autre langage de programmation? (BTW - cette question peut également être appliquée à d'autres langues, comme C #)

vainolo
la source
7
Vous pourriez avoir un peu plus intéressant une question sur "pourquoi les langages à usage général ne sont-ils pas utilisés pour les langages de construction" - je veux dire, C n'est pas non plus un langage de construction. Je suggère également de regarder la cérémonie autour de la compilation d'un seul fichier .java en Java
8
Cela pourrait probablement être généralisé comme "Pourquoi s'embêter avec les DSL?"
FrustratedWithFormsDesigner
1
Une meilleure question pourrait être; pourquoi les IDE / compilateurs / outils sont-ils si mauvais que des outils de construction sont nécessaires en premier lieu.
Brendan
6
@Brendan n'est pas une question, car les outils de construction et les IDE ont des objectifs différents.
jwenting
1
Parce que les langages "à usage général" ne doivent jamais être utilisés à la place des langages bien définis et spécifiques au domaine. Et, si un besoin d'apprendre "encore un autre langage de programmation" vous préoccupe, vous ne devriez pas vraiment programmer, essayez un autre métier.
SK-logic

Réponses:

21

Outil spécifique pour un but spécifique

  • Verbosité

    Les langages à usage général sont souvent trop verbeux. Si je devais gérer une build en Java, je serais très déprimé très rapidement par la taille de la bête. Cependant, il pourrait facilement être gérable à l'aide d'un DSL écrit en Java. Et dans une certaine mesure, c'est ainsi que vous pouvez voir Gradle (pour Groovy) et Buildr (pour Ruby).

  • Difficulté

    Les langages à usage général sont difficiles. Eh bien, je ne pense pas que la programmation soit difficile et ne puisse être reprise par personne, mais le fait est que votre ingénieur en construction n'est pas nécessairement votre programmeur!

  • Objectif

    C'est plus ou moins à l'intersection de la difficulté et de la verbosité . Un langage est conçu dans un but, et nous parlons ici de quelque chose de très spécifique. Alors pourquoi voudriez-vous ou voudriez-vous utiliser un langage à usage général ? Pour les builds, vous avez besoin de:

    • branches et conditions pour gérer des configurations, des environnements, etc. séparés
    • un ensemble d'instructions pour extraire des données de votre environnement,
    • un ensemble d'instructions pour produire des livrables.

    Vous n'avez pas vraiment besoin de beaucoup plus.

Bien sûr, c'est ennuyeux lorsque votre système de construction semble ne pas être suffisamment flexible pour le cas d'utilisation spécial que vous recherchez, mais c'est probablement bien mieux que l'alternative pour la plupart des gens.

C'est probablement pourquoi il y a une polarité entre les personnes qui préfèrent les systèmes de construction déclaratifs à la plupart des onces programmables: je suppose qu'un développeur pourrait avoir une tendance naturelle à chercher des moyens de sortir de la boîte.

Attendez, avons-nous vraiment besoin d'un outil?

Une autre question connexe serait: avons-nous vraiment besoin d'un outil de construction? Le fait qu'ils existent dans toutes les langues n'est-il pas le signe qu'ils comblent une lacune qui ne devrait même pas être là en premier lieu?

Certaines langues ne nécessitent pas nécessairement un outil de construction. Par exemple, la plupart des langages de script n'en ont pas besoin et se résolvent au moment du chargement. Ou prenez Go, dont le compilateur gérera tout pour vous, ce qui est un joli contrepoint: et si un compilateur comme gcc n'avait soudainement pas besoin d'un tas de drapeaux, d'un éditeur de liens et d'un makefile pour tout mourir ensemble? Ou si javac n'avait pas besoin d'un build.xml ou pom.xml pour lui dire quoi faire? La gestion des dépendances ne devrait-elle pas faire directement partie des outils du langage, car les dépendances font partie du programme final?

Cela semble sûrement une approche beaucoup plus simple pour l'utilisateur (le constructeur). Bien que l'on puisse dire qu'ils font juste sous le capot et enlèvent votre choix et vos opportunités d'influencer ce processus de construction (mais alors vous espérez qu'un tel outil autorise des extensions de compilateur et des choses similaires). De plus, nous avions l'habitude de voir les outils et la langue comme deux choses distinctes, donc il peut sembler impur de les avoir soudainement si étroitement couplés.

Je ne pense pas que le langage que vous utilisez pour créer vos programmes soit le problème. C'est le langage que vous utilisez pour programmer, sa plate-forme de base et ses outils qui devraient être importants, et nous progressons toujours à cet égard.


Personnellement, j'ai utilisé make / gmake / autotools / pmk et j'en suis content pour C, et j'ai commencé avec Java quand tout ce que nous avions était make, puis ant, et maintenant je préfère généralement Maven à toutes ces alternatives. Bien que je puisse voir la valeur dans gradle, buildr et autres, mais j'aime la prévalence de maven jusqu'à présent, jusqu'à ce qu'un changement plus important se produise. De plus, j'aime le fait qu'il soit rigide, mais vous laisse toujours la possibilité de contourner cela si nécessaire. Que ce ne soit pas facile est une bonne chose.

C'est un outil de construction. Apprenez simplement à l'embrasser et ne le combattez pas. C'est une bataille perdue. Ou du moins une très très longue.

haylem
la source
J'aime vraiment votre pragmatisme. Ma question est par curiosité. J'utilise maven (ayant utilisé make et ant dans le passé), et il fait de la "magie noire" qui est parfois bonne et parfois mauvaise. Mais c'est toujours magique.
vainolo
1
"Ou si javac n'avait pas besoin d'un build.xml ou pom.xml pour lui dire quoi faire?" - il h. il ne l'a pas fait et ne l'a jamais fait.
user253751
@immibis: c'est discutable. Je n'apprécierais pas vraiment de construire mes projets au bureau avec seulement javac :) Cela nécessiterait certainement un peu de colle avec un Makefile ou un script shell ou à tout le moins des alias shell pour assembler les choses. Ou un programme gigantesque avec tout dans un dossier et tous les deps dans le repo. Pas vraiment quelque chose que j'aimerais! :) Mais c'est un autre débat entièrement, sans rapport avec la question du PO.
haylem
L'intégration du système de construction avec le langage est également problématique pour les projets polyglottes. Si j'utilise à la fois la langue A et la langue B et que je souhaite avoir un processus de génération unique pour eux, quel système de génération de langue dois-je utiliser?
Sebastian Redl
@SebastianRedl Alors, comment le problème devient-il plus facile en introduisant une troisième langue? Choisissez simplement la langue qui vous convient le mieux. (Et bien sûr, si vous avez besoin d'une troisième langue, Java peut aussi l'être.)
Ville Oikarinen
21

Javaest un impératif langue, Ant, Maven, etc. sont déclaratives langues:

Nous pourrions définir la différence comme suit:

  • Programmation impérative: dire à la "machine" comment faire quelque chose, et par conséquent ce que vous voulez arriver se produira.
  • Programmation déclarative: dire à la "machine" ce que vous aimeriez qu'il se passe et laisser l'ordinateur comprendre comment le faire. 1

Les langues de construction le disent au constructeur ce qui doit être fait, d' cela doit être pris, etc. Le moteur qui exécute la construction (qui est écrit dans un langage impératif, comme @ElliottFrisch l'a noté), lit ces instructions et les remplit.

Les langages déclaratifs peuvent sembler plus appropriés dans les scénarios de génération, car les tâches de génération sont généralement les mêmes partout, et elles sont considérées comme plus faciles à gérer et à lire sous cette forme que sous forme de code à part entière.

Uri Agassi
la source
3
Il existe cependant au moins un système de construction qui utilise un langage impératif. Scons utilise Python.
user16764
La rendre impérative n'est pas plus difficile que d'écrire une classe qui peut contenir une liste de dépendances et une méthode pour résoudre ces dépendances. Je soupçonne qu'il y a une autre raison - comme le temps de démarrage de la JVM, peut-être.
2
@Lee: La quasi - totalité des outils de construction utilisés dans le monde Java (Ant, Maven, Gradle, SBT, ...) aussi généralement exécutées sur la machine virtuelle Java (à l'exception du Râteau, Buildr ou Scons, qui peuvent , mais ne pas avoir pour fonctionner sur la JVM).
Jörg W Mittag
6
@vainolo "La plupart des gens n'aiment pas vraiment Ant / Maven / Make" vraiment? Voilà une déclaration audacieuse!
Ben Thurley
1
@BenThurley Les gens que j'aimais faire, pourquoi a été créé fourmi? et si la fourmi était appréciée, pourquoi maven? Et maintenant, pourquoi les gens utilisent Gradle? Mais je conviens que c'est une déclaration audacieuse, et elle n'est appuyée que par des preuves "anecdotiques" de quelques dizaines de développeurs java
vainolo
4

Si vous regardez les caractéristiques d'un système de construction typique, vous trouvez:

  1. Beaucoup de données: noms, commutateurs, paramètres, éléments de configuration, chaînes, etc.
  2. Beaucoup d'interaction avec l'environnement: commandes, variables d'environnement
  3. Un "moteur de construction" relativement simple gérant les dépendances, le threading, la journalisation, etc.

Si vous envisagez d'écrire une série de fichiers de construction en utilisant un langage (Java / C # / Python / etc), vers la troisième ou la quatrième itération, vous vous contenterez (a) de conserver la plupart des données et des commandes externes en tant que données dans quelque chose comme XML (b) écrire le "moteur de construction" dans votre langue préférée.

Vous trouverez également utile de traiter certaines des données de votre XML comme un langage interprété, pour déclencher diverses fonctionnalités dans le moteur de génération. Vous pouvez également interpréter certaines macros ou effectuer des substitutions de chaînes dans les données.

En d'autres termes, vous finiriez avec Make, ou Ant, ou Rake, ou MsBuild. Un langage impératif pour ce qu'il fait bien, et des structures de données pour décrire ce que vous voulez faire, désormais généralement en XML.

david.pfx
la source
2

Un certain nombre de facteurs comptent contre l'utilisation de Java / C ++ / C # dans ces cas.

Tout d'abord, vous devez compiler votre script de génération avant de pouvoir l'exécuter pour créer votre application. Comment spécifieriez-vous les packages, drapeaux, versions de compilateur, chemins d'outils nécessaires pour construire votre script de construction? Certes, vous pouvez trouver un moyen de le contourner, mais il est beaucoup plus simple d'avoir soit un langage qui n'a pas besoin de cette étape de construction (par exemple python) ou un langage que votre outil de construction comprend nativement.

Deuxièmement, les fichiers de construction sont lourds de données alors que Java / C ++ / C # sont beaucoup plus axés sur l'écriture de code et d'algorithmes. Java et ses amis n'ont pas une représentation très succincte de toutes les données que vous souhaitez stocker.

Troisièmement, Java et ses amis ont besoin de beaucoup de passe-partout pour être valides. Le fichier de construction devrait être à l'intérieur d'une méthode à l'intérieur d'une classe avec toutes ses importations. Lorsque vous utilisez un langage de script ou un langage personnalisé, vous pouvez éviter tout ce passe-partout et simplement avoir les détails de construction eux-mêmes.

Winston Ewert
la source
0

Effectivement! Pourquoi ne pas utiliser un puissant et expressif langage pour un problème plus complexe qu'on ne le pense souvent (au départ)? Surtout quand les personnes confrontées au problème sont déjà compétentes avec une telle langue. (La construction est le problème des programmeurs et est le mieux résolu par les programmeurs.)

Je me suis aussi posé cette question il y a des années et j'ai décidé que Java est un bon langage pour définir des builds, en particulier pour des projets Java. Et, en conséquence, j'ai commencé à faire quelque chose à ce sujet.

AVERTISSEMENT : Dans cette réponse, je fais la promotion d' iwant , un système de build que je développe. Mais comme il s'agit de toute façon d'une discussion d'opinion, je suis sûr que ça va.

Je ne m'étendrai pas sur les avantages de Java (puissance et expressivité) ou iwant en particulier. Si vous êtes intéressé, vous pouvez en lire plus sur la page iwant .

Au lieu de cela, je considérerai pourquoi Java (et d'autres GPL) est si facilement rejeté comme impropre à la construction. De nombreuses réponses et commentaires sont de bons exemples d'une telle réflexion. Examinons certains des arguments typiques:

"Java est impératif, mais les builds sont mieux définis de manière déclarative" , pourraient-ils dire.

Vrai. Mais lorsque vous utilisez un langage comme métalangage pour une DSL interne , ce qui compte vraiment, c'est sa syntaxe . Même un langage impératif comme Java peut être trompé pour être déclaratif. S'il semble et se sent déclaratif, il est (à des fins pratiques) déclaratif. Par exemple:

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

Ceci est un véritable exemple du projet de démonstration d'iwant .

En fait, comparez cela à certains systèmes de construction soi-disant déclaratifs qui exposent leurs utilisateurs à des verbes impératifs tels que "tester" ou "compiler". La déclaration ci-dessus ne contient que des noms, pas de verbes. La compilation et le test sont des tâches implicitement gérées par iwant afin d'accorder à l'utilisateur les noms qu'il souhaite. Ce n'est pas la langue. C'est ainsi que vous l'utilisez.

"Java est verbeux"

Oui, beaucoup de code Java est verbeux. Mais encore une fois, ce n'est pas la langue, c'est la façon dont vous l'utilisez. Si une implémentation est verbeuse, il suffit de l'encapsuler derrière une belle abstraction. De nombreuses GPL fournissent des mécanismes adéquats pour cela.

Imaginez simplement l'extrait Java ci-dessus écrit en XML. Remplacez les parenthèses par des équerres et déplacez-les. Et puis dupliquez chaque mot-clé comme une balise de fermeture! Java en tant que syntaxe n'est pas verbeux.

(Je sais, comparer à XML, c'est comme prendre des bonbons à un bébé, mais tant de builds se trouvent être définis en XML.)

"Vous devrez compiler votre script de construction"

Ceci est un point valable. Néanmoins, ce n'est qu'un problème technique mineur à résoudre. J'aurais pu le résoudre en utilisant beanshell ou un autre interprète. Au lieu de cela, je l'ai résolu en le traitant comme un autre problème de construction et en amorçant iwant avec un simple shell ou script ant qui compile et exécute un simple bootstrapper Java.

"Java a passe-partout"

Vrai. Vous devez importer des classes, vous devez mentionner "public", "class" et ainsi de suite. Et ici, de simples DSL externes marquent une première victoire facile.

Et si votre projet est si banal que ce passe-partout est important, bravo. Votre problème n'est pas difficile et peu importe comment vous le résolvez.

Mais de nombreux projets nécessitent bien plus que la compilation, le rapport de couverture et le packaging. Si le passe-partout de Java est acceptable pour les problèmes des clients, pourquoi ne pas créer des problèmes? Pourquoi fabriquer des chaussures uniquement pour les enfants des autres?

Ville Oikarinen
la source
0

Une chose que je ne pense pas que les autres réponses aient abordée est que les limitations et la transparence de ces langages de construction sont une partie énorme de ce qui les rend utiles. Prenons Maven, par exemple. Oui, il exécute des builds mais il définit également des dépendances. Cela permet à une génération Maven de supprimer ces dépendances et de regarder leurs dépendances, etc.

Demandez-vous si cela a été fait directement avec Java. L'outil de génération verrait qu'il existe une dépendance. Il faudrait ensuite dérouler une autre application Java et l'exécuter pour déterminer quelles sont ses dépendances. Mais pour Maven, il regarde simplement les déclarations de dépendance. Le fichier de construction maven est transparent. Un langage complet de Turing est intrinsèquement non transparent et est donc inférieur à certaines fins telles que celle-ci.

JimmyJames
la source
Comment Gradle s'y intègre-t-il? Il définit les dépendances dans un style déclaratif, en utilisant un langage à usage général (Groovy). Dans un outil basé sur Groovy, JavaScript ou Lisp, il est naturel d'utiliser le compilateur ou l'interpréteur du langage pour analyser les déclarations, que vous souhaitiez simplement les lire ou les `` exécuter '' (appliquez une fonction). Cette dualité de code et de données ne fait pas partie de l'idiome Java généralement accepté, mais pas impossible. Turing l'exhaustivité n'empêche pas une bonne représentation des données. Cela ouvre la possibilité que vos données fassent quelque chose que vous ne pensiez pas faire.
joshp
@joshp Je ne connais pas Gradle. Il est décrit comme une DSL et les choses semblent plutôt déclaratives. Être basé sur Groovy ne signifie pas nécessairement qu'il est équivalent à Groovy dans sa puissance. Vous seriez probablement mieux placé pour dire si Gradle est en fait un langage complet de Turing. Les exemples de dépendance que j'ai examinés semblent assez simples. Pouvez-vous utiliser des expressions Groovy arbitraires dans des choses comme les déclarations de dépendance?
JimmyJames
Personnellement, je n'aime même pas les dépendances transitives. Souvent, elles provoquent juste des surprises dans le chemin de classe (plusieurs versions incompatibles de bibliothèques). C'est pourquoi maven a l'élément exclude, mais les tracas n'en valent pas seulement la peine. Les dépendances explicites simplifient la vie. Pourtant, les dépendances transitives peuvent être implémentées avec Java. J'ai fait quelque chose comme ça avec iwant en réutilisant les définitions de build d'autres projets.
Ville Oikarinen
@VilleOikarinen Je suis surtout d'accord avec vous. Je pense que cela provoque également une tonne de ballonnements car il n'y a pas de coût perçu pour attirer plus de dépendances même si vous ne les utilisez pas. Cependant, dans le contexte de cette réponse, je ne commente pas la valeur ou la sagesse de cette fonctionnalité, mais la façon dont l'utilisation d'une DSL est utile pour y parvenir.
JimmyJames
1
@VilleOikarinen Je pense que nous avons en quelque sorte atteint la fin de cela, mais je veux juste préciser que je ne parle pas de pom / maven. C'est un exemple de build DSL mais je n'y pense pas beaucoup. Je l'utilise à contrecœur et je pense que c'est maladroit. Mais ce qui a pom si dominant, ce sont les déclarations de dépendance. J'ai utilisé Buildr pendant un certain temps et il lit pom pour les dépendances mais il ne les utilise pas pour les spécifications de construction. Il existe un certain nombre d'outils qui ne sont pas basés sur Java qui comprennent ce pom mais AFAIK, tout ce qui les intéresse, ce sont les dépendances.
JimmyJames