¿Por qué no se usa Java como lenguaje de compilación?

24

Si Java es un lenguaje de propósito general, y construir un programa es algo que se puede describir usando el lenguaje Java, ¿por qué no es esta la mejor manera de escribir archivos de compilación y en su lugar utilizamos herramientas como Ant, Maven y Gradle? ¿No sería más sencillo y también eliminaría la necesidad de aprender otro lenguaje de programación más? (Por cierto, esta pregunta también se puede aplicar a otros idiomas, como C #)

vainolo
fuente
77
Es posible que tenga una pregunta un poco más interesante sobre "por qué no se utilizan lenguajes de propósito general para los lenguajes de compilación". Es decir, C tampoco es un lenguaje de compilación. También sugeriría mirar la ceremonia en torno a la compilación de un solo archivo .java en Java
8
Esto probablemente podría generalizarse como "¿Por qué molestarse con DSL?"
FrustratedWithFormsDesigner
1
Una mejor pregunta podría ser; ¿Por qué los IDE / compiladores / herramientas son tan malos que las herramientas de compilación son necesarias en primer lugar?
Brendan
66
@Brendan no es una pregunta, ya que las herramientas de construcción y los IDE tienen diferentes propósitos.
Jwent
1
Porque los lenguajes de "propósito general" nunca deberían usarse en lugar de los bien definidos, simples lenguajes específicos de dominio. Y, si le preocupa la necesidad de aprender "otro lenguaje de programación más", realmente no debería estar programando, pruebe con otro oficio.
SK-logic

Respuestas:

21

Herramienta específica para un propósito específico

  • Verbosidad

    Los lenguajes de uso general son a menudo demasiado detallados. Si tuviera que administrar una compilación en Java, me deprimiría muy rápidamente por el tamaño de la bestia. Sin embargo, podría ser fácilmente manejable usando un DSL escrito en Java. Y hasta cierto punto así es como puedes ver Gradle (para Groovy) y Buildr (para Ruby).

  • Dificultad

    Los lenguajes de uso general son difíciles. Bueno, no creo que la programación sea difícil y nadie pueda aprenderla, pero el punto es: ¡tu ingeniero de construcción no es necesariamente tu programador!

  • Propósito

    Eso es más o menos en la intersección de dificultad y verbosidad . Un lenguaje está diseñado para un propósito, y aquí estamos hablando de algo muy específico. Entonces, ¿por qué necesitarías o querrías usar un lenguaje de propósito general ? Para las compilaciones, necesitas:

    • ramas y condicionales para manejar configuraciones separadas, entornos, etc.
    • un conjunto de instrucciones para extraer datos de su entorno,
    • Un conjunto de instrucciones para producir entregables.

    Realmente no necesitas mucho más.

Claro que es molesto cuando su sistema de compilación parece que no es lo suficientemente flexible para ese caso de uso especial que está buscando, pero probablemente sea mucho mejor que la alternativa para la mayoría de las personas.

Esa es probablemente la razón por la cual hay una polaridad entre las personas que prefieren los sistemas de compilación declarativa en lugar de la mayoría de las ocasiones programables: supongo que un desarrollador podría tener una tendencia natural a buscar formas de salir de la caja.

Espera, ¿realmente necesitamos una herramienta?

Otra pregunta relacionada sería: ¿realmente necesitamos una herramienta de compilación? ¿No es el hecho de que existan en todos los idiomas la señal de que llenan un vacío que ni siquiera debería estar allí en primer lugar?

Algunos idiomas no requieren necesariamente una herramienta de compilación. Por ejemplo, la mayoría de los lenguajes de script no necesitan uno y se resuelven en el momento de la carga. O tome Go, cuyo compilador se encargará de todo por usted, lo cual es un buen contrapunto: ¿qué pasaría si un compilador como gcc de repente no necesitara un montón de banderas, un enlazador y un archivo MAKE para morir todo junto? ¿O si javac no necesitaba un build.xml o pom.xml para decirle qué hacer? ¿No debería la gestión de dependencias directamente ser parte de las herramientas propias del lenguaje, ya que las dependencias son parte del programa final?

Seguramente parece un enfoque mucho más simple para el usuario (el constructor). Aunque se podría argumentar que lo están haciendo de manera oculta y le están quitando su elección y oportunidades para influir en ese proceso de compilación (pero entonces esperaría que tal herramienta permita extensiones del compilador y cosas similares). Además, solíamos ver las herramientas y el lenguaje como dos cosas separadas, por lo que podría parecer inseguro de repente tenerlas tan estrechamente unidas.

No creo que el lenguaje que usa para construir sus programas sea el problema. Lo que debería importar es el lenguaje que usa para programar y su plataforma central y herramientas, y todavía estamos avanzando en eso.


Personalmente, utilicé make / gmake / autotools / pmk y estuve contento con ellos para C, y comencé con Java cuando todo lo que teníamos era make, luego hormiga, y ahora generalmente prefiero a Maven a todas estas alternativas. Aunque puedo ver el valor en gradle, buildr y otros, pero hasta ahora me gusta la prevalencia de maven, hasta que se produce un cambio más significativo. Además, me gusta que sea rígido, pero aún así te deja la capacidad de evitarlo si es necesario. Que no es fácil es algo bueno.

Es una herramienta de construcción. Solo aprende a abrazarlo y no luchar contra él. Es una batalla perdida. O al menos uno muy muy largo.

haylem
fuente
Realmente me gusta tu pragmatismo. Mi pregunta es por curiosidad. Uso maven (habiendo usado make y ant en el pasado), y hace "magia negra", que a veces es buena y otras es mala. Pero sigue siendo mágico.
vainolo
1
"¿O si javac no necesitara build.xml o pom.xml para decirle qué hacer?" - je. no lo hace y nunca lo hizo.
user253751
@immibis: eso es discutible. Realmente no me gustaría construir mis proyectos en la oficina con solo javac :) Sin duda, requeriría un poco de pegamento con un Makefile o un script de shell o, al menos, alias de shell para armar las cosas. O un programa gigantesco con todo en una carpeta y todos los departamentos en el repositorio. ¡Realmente no es algo que me gustaría! :) Pero ese es otro debate completamente, sin relación con la pregunta del OP.
haylem
Integrar el sistema de compilación con el lenguaje también es problemático para proyectos políglotas. Si uso los idiomas A y B y quiero tener un solo proceso de compilación para ellos, ¿qué sistema de compilación de idiomas utilizo?
Sebastian Redl
@SebastianRedl Entonces, ¿cómo se hace más fácil el problema al introducir un tercer idioma? Simplemente elija el idioma que funcione mejor para usted. (Y, por supuesto, si necesita un tercer idioma, Java también puede serlo.)
Ville Oikarinen
21

Javaes un imperativo lengua, Ant, Maven, etc, son declarativas idiomas:

Podríamos definir la diferencia de la siguiente manera:

  • Programación imperativa: decirle a la "máquina" cómo hacer algo, y como resultado lo que quiere que suceda sucederá.
  • Programación declarativa: decirle a la "máquina" lo que le gustaría que suceda, y dejar que la computadora descubra cómo hacerlo. 1

Los lenguajes de compilación le dicen al constructor qué se debe hacer, desde dónde se debe tomar, etc. El motor que ejecuta la compilación (que está escrito en un lenguaje imperativo, como ha notado @ElliottFrisch), lee estas instrucciones y las cumple.

Los lenguajes declarativos pueden parecer más apropiados en escenarios de compilación, ya que las tareas de compilación generalmente son las mismas en todas partes, y se considera más fácil de mantener y legible en esa forma que en forma de código completo.

Uri Agassi
fuente
3
Sin embargo, hay al menos un sistema de compilación que usa un lenguaje imperativo. Scons usa Python.
user16764
Sin embargo, hacer que sea imperativo no es más difícil que escribir una clase que pueda contener una lista de dependencias y un método para resolver esas dependencias. Sospecho que hay otra razón, tal como el tiempo de inicio de JVM, tal vez.
2
@Lee: Casi todas las herramientas de compilación utilizadas en el mundo Java (Ant, Maven, Gradle, SBT, ...) también suelen ejecutarse en la JVM (con la excepción de Rake, Buildr o Scons, que pueden , pero no tienen para correr en la JVM).
Jörg W Mittag
66
@vainolo "¿A la mayoría de la gente no le gusta realmente Ant / Maven / Make"? Esa es una declaración audaz!
Ben Thurley
1
@BenThurley A la gente le gustaba hacer, ¿por qué se creó la hormiga? y si a la hormiga le gustaba, ¿por qué a Maven? ¿Y ahora por qué la gente usa Gradle? Pero estoy de acuerdo en que es una declaración audaz, y solo está respaldada por evidencia "anecdótica" de algunas decenas de desarrolladores de Java
vainolo
4

Si observa las características de un sistema de compilación típico, encontrará:

  1. Gran cantidad de datos: nombres, conmutadores, configuraciones, elementos de configuración, cadenas, etc.
  2. Mucha interacción con el entorno: comandos, variables de entorno.
  3. Un "motor de compilación" relativamente sencillo que maneja dependencias, subprocesos, registros, etc.

Si se propone escribir una serie de archivos de compilación utilizando algún lenguaje (Java / C # / Python / etc.), aproximadamente en la tercera o cuarta iteración se conformaría con (a) mantener la mayoría de los datos y comandos externos como datos en algo como XML (b) escribiendo el "motor de compilación" en su idioma favorito.

También le resultará útil tratar algunos de los datos en su XML como un lenguaje interpretado, para activar varias características en el motor de compilación. También puede interpretar algunas macros o realizar sustituciones de cadenas en los datos.

En otras palabras, terminarías con Make, o Ant, o Rake, o MsBuild. Un lenguaje imperativo para las cosas que hace bien, y estructuras de datos para describir lo que quiere hacer, ahora generalmente en XML.

david.pfx
fuente
2

Varios factores cuentan contra el uso de Java / C ++ / C # en estos casos.

En primer lugar, tendría que compilar su script de compilación antes de poder ejecutarlo para compilar su aplicación. ¿Cómo especificaría los paquetes, las banderas, las versiones del compilador, las rutas de herramientas necesarias para construir su script de compilación? Ciertamente, podría encontrar una forma de evitarlo, pero es mucho más sencillo tener un lenguaje que no necesite ese paso de compilación (por ejemplo, python) o un lenguaje que su herramienta de compilación comprenda de forma nativa.

En segundo lugar, los archivos de compilación tienen muchos datos, mientras que Java / C ++ / C # están mucho más orientados a escribir código y algoritmos. Java y sus amigos no tienen una representación muy sucinta de todos los datos que desea almacenar.

En tercer lugar, Java y sus amigos necesitan mucha repetitiva para ser válidos. El archivo de compilación tendría que estar dentro de un método dentro de una clase con todas sus importaciones. Al usar un lenguaje de secuencias de comandos o un lenguaje personalizado, puede evitar toda esa estructura repetitiva y solo tener los detalles de compilación.

Winston Ewert
fuente
0

¡En efecto! ¿Por qué no usar un lenguaje poderoso y expresivo para un problema que es más complejo de lo que la gente piensa (inicialmente)? Especialmente cuando las personas que enfrentan el problema ya son competentes con dicho lenguaje. (La construcción es un problema de los programadores y la mejor manera de resolverla los programadores).

También me hice esta pregunta hace años y decidí que Java es un buen lenguaje para definir compilaciones, especialmente para proyectos Java. Y, como resultado, comencé a hacer algo al respecto.

DESCARGO DE RESPONSABILIDAD : En esta respuesta, estoy promoviendo iwant , un sistema de compilación que estoy desarrollando. Pero dado que esta es una discusión obstinada de todos modos, estoy seguro de que está bien.

No voy a dar más detalles sobre los beneficios de Java (potencia y expresividad) ni quiero específicamente. Si está interesado, puede leer más en la página de iwant .

En cambio, consideraré por qué Java (y otras GPL) se descartan tan fácilmente como inadecuados para la construcción. Muchas respuestas y comentarios aquí son buenos ejemplos de tal pensamiento. Consideremos algunos de los argumentos típicos:

"Java es imprescindible, pero las compilaciones se definen mejor de manera declarativa" , podrían decir.

Cierto. Pero cuando se usa un lenguaje como metalenguaje para un DSL interno , lo que realmente cuenta es su sintaxis . Incluso un lenguaje imperativo como Java puede ser engañado para ser declarativo. Si se ve y se siente declarativo, es (para fines prácticos) declarativo. Por ejemplo:

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

Este es un ejemplo real del proyecto de demostración de iwant .

De hecho, compare esto con algunos sistemas de compilación supuestamente declarativos que exponen a sus usuarios a verbos imperativos como "prueba" o "compilación". La declaración anterior contiene solo sustantivos, no verbos. Compilar y probar son tareas que iwant maneja implícitamente para otorgar al usuario los sustantivos que desea. No es el idioma Así es como lo usas.

"Java es detallado"

Sí, una gran cantidad de código Java es detallado. Pero de nuevo, no es el lenguaje, es cómo lo usas. Si una implementación es detallada, simplemente encapsúlela detrás de una buena abstracción. Muchas GPL proporcionan mecanismos adecuados para esto.

Solo imagine el fragmento de Java anterior escrito en XML. Reemplace los paréntesis con corchetes angulares y muévalos. ¡Y luego duplique cada palabra clave como etiqueta de cierre! Java como sintaxis no es detallada.

(Lo sé, comparar con XML es como quitarle un caramelo a un bebé, pero muchas construcciones están definidas en XML).

"Tendrías que compilar tu script de compilación"

Este es un punto válido. Sin embargo, es solo un problema técnico menor a resolver. Podría haberlo resuelto usando beanshell o algún otro intérprete. En cambio, lo resolví tratándolo como un problema más de compilación y bootstrapping con un simple shell o script de hormiga que compila y ejecuta un simple bootstrapper de Java.

"Java tiene repetitivo"

Cierto. Debe importar clases, debe mencionar "public", "class", etc. Y aquí, las DSL externas simples obtienen una victoria inicial fácil.

Y si su proyecto es tan trivial que este estándar es significativo, felicidades. Su problema no es difícil y realmente no importa cómo lo resuelva.

Pero muchos proyectos necesitan mucho más que compilación, informe de cobertura y empaque. Si el estándar de Java es aceptable para los problemas de los clientes, ¿por qué no crear problemas? ¿Por qué hacer zapatos solo para los hijos de otros?

Ville Oikarinen
fuente
0

Una cosa que no creo que las otras respuestas hayan abordado es que las limitaciones y la transparencia de estos lenguajes de compilación son una gran parte de lo que los hace útiles. Tomemos a Maven, por ejemplo. Sí, ejecuta compilaciones pero también define dependencias. Esto permite que una compilación de Maven elimine esas dependencias y observe sus dependencias y así sucesivamente.

Considere si esto se hizo con Java directamente. La herramienta de compilación vería que hay una dependencia. Luego necesitaría desplegar otra aplicación Java y ejecutarla para determinar cuáles son sus dependencias. Pero para Maven, simplemente mira las declaraciones de dependencia. El archivo de compilación de Maven es transparente. Un lenguaje completo de Turing es inherentemente no transparente y, por lo tanto, es inferior para algunos fines como este.

JimmyJames
fuente
¿Cómo encaja Gradle en esto? Define las dependencias en un estilo declarativo, utilizando un lenguaje de propósito general (Groovy). En una herramienta basada en Groovy, JavaScript o Lisp, es natural usar el compilador o el intérprete del lenguaje para analizar las declaraciones, ya sea que solo desee leerlas o 'ejecutarlas' (aplique alguna función). Esa dualidad de código y datos no es parte del lenguaje de Java generalmente aceptado, aunque no es imposible. La integridad de Turing no impide una buena representación de datos. Abre la posibilidad de que sus datos hagan algo que no esperaba que hiciera.
joshp
@joshp No estoy familiarizado con Gradle. Se describe como un DSL y las cosas parecen bastante declarativas. Estar basado en Groovy no significa necesariamente que sea equivalente a Groovy en su poder. Probablemente estarías en una mejor posición para decir si Gradle es de hecho un lenguaje completo de Turing. Los ejemplos de dependencia que miré parecen bastante simples. ¿Puedes usar expresiones Groovy arbitrarias en cosas como declaraciones de dependencia?
JimmyJames
Personalmente, ni siquiera me gustan las dependencias transitivas. A menudo solo causan sorpresas en el classpath (múltiples versiones incompatibles de bibliotecas). Es por eso que Maven tiene el elemento de exclusión, pero la molestia no solo vale la pena. Las dependencias explícitas hacen la vida más simple. Aún así, las dependencias transitivas se pueden implementar con Java. He hecho algo así con iwant reutilizando las definiciones de compilación de otros proyectos.
Ville Oikarinen
@VilleOikarinen Estoy totalmente de acuerdo contigo. Creo que también causa un montón de hinchazón ya que no se percibe un costo para atraer más dependencias, incluso si no las usa. Sin embargo, en el contexto de esta respuesta, no estoy comentando sobre el valor o la sabiduría de esa característica, sino sobre cómo el uso de un DSL es útil para lograrlo.
JimmyJames
1
@VilleOikarinen Creo que hemos llegado al final de esto, pero solo quiero aclarar que no estoy hablando de pom / maven. Este es un ejemplo de un DSL de compilación, pero no pienso mucho en ello. Lo uso de mala gana y creo que es torpe. Pero lo que tiene a Pom tan dominante son las declaraciones de dependencia. Usé Buildr por un tiempo y lee pom para dependencias, pero no las usa para las especificaciones de compilación. Hay una serie de herramientas que no están basadas en Java que entienden este pom pero AFAIK, lo único que les importa son las dependencias.
JimmyJames