Tuiteo contenido técnico que considero interesante, pero los tuits divertidos son los que tienen más participación. Asistí a la conferencia de JavaLand en marzo, me topé con el stand de Gradle y encontré esta joya:
Por supuesto, en algún momento, un fanboy secuestró el hilo y reclamó la supuesta superioridad de Gradle. En esta publicación, me gustaría arrojar algo de luz sobre mi postura, para poder dirigir a las personas hacia ella en lugar de desacreditar el mismo "razonamiento" repetidamente.
Para manejar esto, necesito volver en el tiempo. El desarrollo de software es un campo que cambia rápidamente y gran parte de nuestra comprensión se basa en la experiencia personal. Así que aquí está el mío.
Empecé a desarrollar en Java en 2002. En ese momento, no había herramientas de compilación: compilábamos y construíamos a través del IDE. Para que conste, primero usé Visual Age para Java; luego, me mudé a Borland JBuilder.
Construir con un IDE tiene un gran problema: cada desarrollador tiene configuraciones dedicadas, por lo que la generación de artefactos depende de la combinación desarrollador-máquina.
Las compilaciones no repetibles son un problema antiguo. Mi primera experiencia con compilaciones repetibles es Apache Ant:
Apache Ant es una biblioteca de Java y una herramienta de línea de comandos cuya misión es impulsar los procesos descritos en los archivos de compilación como objetivos y puntos de extensión que dependen unos de otros. El principal uso conocido de Ant es la creación de aplicaciones Java. Ant proporciona una serie de tareas integradas que permiten compilar, ensamblar, probar y ejecutar aplicaciones Java. Ant también se puede utilizar de forma eficaz para crear aplicaciones que no sean Java, por ejemplo, aplicaciones C o C++. En términos más generales, Ant se puede utilizar para pilotear cualquier tipo de proceso que se pueda describir en términos de objetivos y tareas.
Ant se basa en tres abstracciones principales:
javac
para compilar archivos Java, war
para ensamblar un archivo web, etc. Ant proporciona muchas tareas listas para usar, pero permite agregar tareas personalizadas.
Pronto me volví "fluido" en Ant. Como consultor, fui de empresa en empresa, de proyecto en proyecto. Inicialmente, principalmente configuré Ant, pero Ant se generalizó con el paso del tiempo y encontré configuraciones de Ant existentes. Fui constante en mis proyectos, pero otros proyectos eran muy diferentes entre sí.
Cada vez que llegaba a un nuevo proyecto, tenía que leer detenidamente la configuración de Ant para comprender la compilación personalizada. Además, la estructura de cada proyecto era diferente. Algunos ponen sus fuentes en src
, algunos en sources
, algunos en una estructura anidada, etc.
Recuerdo una vez un archivo de compilación genérico que intentó acomodar la totalidad de las necesidades del proyecto de una organización. Definió más de 80 objetivos en más de 2000 líneas de XML. Me tomó una cantidad de tiempo no trivial entender cómo usarlo con ayuda e incluso más tiempo para poder modificarlo sin interrumpir los proyectos.
El proyecto anterior me hizo pensar mucho. Quería mejorar la situación ya que los mantenedores ya habían superado los límites de Ant. En ese momento, estaba trabajando con mi amigo Freddy Mallet (de la fama de Sónar). Hablamos y me señaló a Maven. Una vez construí un proyecto con Maven pero no tenía otra experiencia previa. Estudié la documentación durante horas y, a través de intentos de prueba y error, bajo la tutela de Freddy, migré todo el archivo de compilación de Ant a un POM principal simple.
En Ant, necesitarías definir todo en cada proyecto. Por ejemplo, Ant requiere configurar la ubicación de los archivos Java para la compilación; Maven asume que están bajo src/main/java
, aunque es posible anularlo. Maven revolucionó el campo de construcción de Java con su enfoque de Convención sobre Configuración . Hoy en día, muchos programas ofrecen una configuración inteligente por defecto.
Para los desarrolladores que pasan de un proyecto a otro, como hice yo, significa que hay mucha menos carga cognitiva al unirse a un nuevo proyecto. Espero que las fuentes de Java estén ubicadas en src/main/java
. Las convenciones de Maven continúan más allá de la estructura del proyecto. También definen el ciclo de vida del proyecto, desde la compilación hasta la carga del artefacto en un registro remoto, a través de pruebas unitarias y de integración.
Finalmente, los desarrolladores junior tienden a ignorarlo, pero Maven definió el término gestión de dependencias . Introdujo la idea de los registros de artefactos, donde uno puede descargar dependencias inmutables y enviar artefactos. Antes de ese momento, cada proyecto tenía que almacenar dependencias en su repositorio dedicado.
Para que conste, había un par de dependencias almacenadas en el proyecto mencionado anteriormente. Cuando migré de Ant a Maven, tuve que encontrar la versión de dependencia exacta. Para la mayoría, fue sencillo, ya que estaba en el nombre del archivo o en el manifiesto del JAR. Uno, sin embargo, había sido actualizado con clases adicionales.
Hasta aquí la inmutabilidad.
Maven tuvo una profunda influencia en todas las herramientas de compilación posteriores: se definieron a sí mismas en referencia a Maven.
El reclamo principal de Gradle era corregir las deficiencias de Maven, o al menos lo que percibía como tal. Si bien Maven no está exento de reproches, Gradle asumió que el problema más importante era su falta de flexibilidad. Es una suposición sorprendente porque eso fue precisamente lo que Maven mejoró sobre Ant. Los proyectos de Maven tienen estructuras similares y usan el mismo ciclo de vida: el principio de menor sorpresa en efecto. Por el contrario, Gradle permite personalizar casi todos los aspectos de la compilación, incluido el ciclo de vida.
Antes de confrontar el argumento de la flexibilidad, permítanme reconocer dos excelentes funciones originales de Gradle que Maven implementó después: el demonio de Gradle y el contenedor de Gradle.
Maven y Gradle son aplicaciones Java que se ejecutan en JVM. Iniciar una JVM es costoso en términos de tiempo y recursos. El beneficio es que JVM de ejecución prolongada optimizará el código JIT-ed con el tiempo. Para tareas a corto plazo, el beneficio es nulo e incluso perjudicial si se tiene en cuenta el tiempo de inicio de la JVM. A Gradle se le ocurrió el demonio Gradle. Cuando ejecute Gradle, buscará un demonio en ejecución. Si no, comenzará uno nuevo. La aplicación de línea de comandos delegará todo al daemon. Como su nombre lo indica, el daemon no se detiene cuando finaliza la línea de comando. El daemon aprovecha los beneficios de la JVM.
Lo más probable es que su aplicación sobreviva a sus herramientas de compilación actuales. ¿Qué sucede cuando necesita corregir un error dentro de cinco años, solo para darse cuenta de que la herramienta de compilación del proyecto no está disponible en línea? La idea detrás del envoltorio de Gradle es mantener la versión exacta de Gradle junto con el proyecto y solo el código suficiente para descargar la versión completa a través de Internet. Como efecto secundario, los desarrolladores no necesitan instalar Gradle localmente; todos utilizan la misma versión, evitando cualquier discrepancia.
Gradle trajo las dos excelentes características anteriores que integró Maven, lo que demuestra que la competencia es buena. A pesar de esto, todavía no encuentro ningún beneficio de Gradle.
Trataré de alejar el lado emocional. Al principio, el marketing de Gradle intentó menospreciar a Maven en todas las ocasiones posibles, publicó gráficos de comparación locos y, en general, fue muy agresivo en su comunicación. Digamos que esta fase duró mucho más de lo que sería aceptable para una empresa joven que intenta encontrar su lugar en el mercado. Se podría decir que Gradle fue muy edípico en su enfoque: tratar de matar a su "padre" Maven. Finalmente, después de todos esos años, parece que se ha dado cuenta y ahora "ama a Maven".
Recuerde que antes de que Maven se hiciera cargo, todos los proyectos de Ant eran ad hoc. Maven puso fin a eso. Trajo la ley al Mundo Salvaje Oeste de proyectos personalizados. Puede estar en desacuerdo con la ley, pero es la ley de todos modos, y todos deben cumplirla. Los estándares de Maven están tan arraigados que, aunque es posible anular algunos parámetros, por ejemplo , la ubicación de la fuente, nadie lo hace nunca.
Experimenté dos síntomas de la flexibilidad de Gradle. Sospecho que existen muchos más.
Maven gestiona las pruebas de integración en cuatro fases, ejecutadas en orden:
pre-integration-test
: configure cualquier cosa que necesiten las pruebasintegration-test
: ejecutar las pruebaspost-integration-test
: limpiar los recursos, si los hayverify
: actuar sobre los resultados de las pruebas
Nunca utilicé las fases previa y posterior, ya que cada prueba tenía una lógica de configuración y desmontaje dedicada.
Por otro lado, Gradle no tiene noción alguna de pruebas de integración . Sin embargo, los fanáticos de Gradle le explicarán con gusto que puede agregar las fases que desee. De hecho, Gradle permite la "personalización" del ciclo de vida: puede agregar tantas fases adicionales en el ciclo de vida regular como desee.
Es un lío, para cada proyecto tendrá que pensar tanto en la cantidad de fases requeridas como en su nombre: integration-test
, integration-tests
, integration-testing
, it
(para los perezosos), etc. Las opciones son infinitas.
Maven trata cada proyecto como un proyecto estándar regular. Y si tiene necesidades específicas, es posible escribir un complemento para eso. Escribir un complemento de Maven definitivamente no es divertido; por lo tanto, solo escribe uno cuando es necesario, no solo porque ha decidido que la ley no se aplica a usted.
Gradle afirma que la falta de flexibilidad es un problema; por lo tanto, quiere arreglarlo. Mantengo lo contrario: la falta de flexibilidad para mi herramienta de compilación es una característica, no un error. Gradle facilita la piratería de la compilación. Por lo tanto, cualquiera que piense que su proyecto es un copo de nieve especial y merece una personalización, lo hará felizmente. Verificación de la realidad: rara vez es el caso; cuando lo es, es para marcos, no para proyectos regulares. Los defensores de Gradle dicen que todavía ofrece estándares y permite una fácil configuración. El meollo del asunto es que no es un estándar si se puede cambiar a voluntad de cualquiera.
Gradle es la herramienta de compilación de facto para proyectos de Android . En una de las empresas para las que trabajé, alguien escribió un código Groovy personalizado en la compilación de Gradle para ejecutar Sonar y enviar las métricas a la instancia interna de Sonar. No había un complemento de Sonar listo para usar en ese momento, o supongo que no fue suficiente. Hasta ahora, todo bien.
Cuando otro equipo creó el segundo proyecto de Android de la empresa, copiaron y pegaron la estructura del primer proyecto y el archivo de compilación. Lo más inteligente habría sido, en este momento, crear un complemento interno de Gradle a partir del código específico de Sonar. Pero no lo hicieron porque Gradle facilitó la piratería de la compilación. Y yo, el que odia Gradle, me encargué de crear el complemento. Podría haber sido una mejor experiencia de desarrollador, por decir lo menos. Al carecer de documentación de calidad y usar un lenguaje sin tipo (Groovy), usé la consola para imprimir la estructura de los objetos para progresar.
La competencia es buena y Gradle ha traído nuevas ideas que Maven integró, el contenedor y el demonio. Sin embargo, Gradle se basa en la premisa de que la flexibilidad es buena, mientras que mi experiencia me ha demostrado lo contrario. Ant era muy flexible y la carga cognitiva para pasar de un proyecto a otro era alta.
Nosotros, los desarrolladores, somos seres humanos: nos gusta pensar que nuestros proyectos son diferentes a los demás. La mayoría de las veces, no lo son. La personalización es solo una forma de satisfacer nuestro ego. Las herramientas de construcción flexibles nos permiten implementar dicha personalización, ya sea garantizada o no.
Las personalizaciones irrelevantes no aportan ningún beneficio y son fáciles de desarrollar pero costosas de mantener. Si la gestión de activos de software es parte de mis responsabilidades, siempre elegiré la estabilidad sobre la flexibilidad para mi herramienta de compilación.
Publicado originalmente en A Java Geek el 6 de agosto de 2023