¿Por qué usar un sistema de compilación?

Informar un problema Ver fuente Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

En esta página, se explica qué son los sistemas de compilación, qué hacen, por qué deberías usar uno y por qué los compiladores y los secuencias de comandos de compilación no son la mejor opción a medida que tu organización comienza a crecer. Está dirigido a desarrolladores que no tienen mucha experiencia con un sistema de compilación.

¿Qué es un sistema de compilación?

Fundamentalmente, todos los sistemas de compilación tienen un propósito sencillo: transforman el código fuente escrito por los ingenieros en archivos binarios ejecutables que pueden leer las máquinas. Los sistemas de compilación no solo son para el código escrito por humanos, sino que también permiten que las máquinas creen compilaciones automáticamente, ya sea para pruebas o para lanzamientos a producción. En una organización con miles de ingenieros, es común que la mayoría de las compilaciones se activen automáticamente en lugar de que los ingenieros las activen directamente.

¿No puedo simplemente usar un compilador?

La necesidad de un sistema de compilación podría no ser evidente de inmediato. La mayoría de los ingenieros no usan un sistema de compilación mientras aprenden a programar: la mayoría comienza invocando herramientas como gcc o javac directamente desde la línea de comandos, o el equivalente en un entorno de desarrollo integrado (IDE). Siempre y cuando todo el código fuente esté en el mismo directorio, un comando como este funciona bien:

javac *.java

Esto indica al compilador de Java que tome cada archivo fuente de Java en el directorio actual y lo convierta en un archivo de clase binario. En el caso más simple, esto es todo lo que necesitas.

Sin embargo, en cuanto el código se expande, comienzan las complicaciones. javac es lo suficientemente inteligente como para buscar en los subdirectorios del directorio actual el código que se importará. Sin embargo, no tiene forma de encontrar código almacenado en otras partes del sistema de archivos (quizás una biblioteca compartida por varios proyectos). También solo sabe cómo compilar código Java. Los sistemas grandes suelen incluir diferentes partes escritas en una variedad de lenguajes de programación con redes de dependencias entre esas partes, lo que significa que ningún compilador para un solo lenguaje puede compilar todo el sistema.

Una vez que trabajas con código de varios lenguajes o varias unidades de compilación, la compilación de código ya no es un proceso de un solo paso. Ahora debes evaluar de qué depende tu código y compilar esas partes en el orden adecuado, posiblemente usando un conjunto diferente de herramientas para cada parte. Si cambia alguna dependencia, debes repetir este proceso para evitar depender de archivos binarios obsoletos. Para una base de código de tamaño incluso moderado, este proceso se vuelve rápidamente tedioso y propenso a errores.

El compilador tampoco sabe cómo controlar las dependencias externas, como los archivos JAR de terceros en Java. Sin un sistema de compilación, podrías administrar esto descargando la dependencia de Internet, colocándola en una carpeta lib en el disco duro y configurando el compilador para que lea las bibliotecas de ese directorio. Con el tiempo, es difícil mantener las actualizaciones, las versiones y la fuente de estas dependencias externas.

¿Qué sucede con las secuencias de comandos de shell?

Supongamos que tu proyecto de pasatiempo comienza siendo lo suficientemente simple como para que puedas compilarlo solo con un compilador, pero comienzas a tener algunos de los problemas descritos anteriormente. Quizás aún no creas que necesitas un sistema de compilación y puedes automatizar las partes tediosas con algunas secuencias de comandos simples que se encargan de compilar las cosas en el orden correcto. Esto ayuda durante un tiempo, pero, muy pronto, comienzas a tener aún más problemas:

  • Se vuelve tedioso. A medida que tu sistema se vuelve más complejo, comienzas a dedicar casi el mismo tiempo a trabajar en tus secuencias de comandos de compilación que en el código real. Depurar secuencias de comandos de shell es doloroso, y cada vez se agregan más soluciones alternativas una sobre otra.

  • Es lento. Para asegurarte de que no dependías accidentalmente de bibliotecas obsoletas, el script de compilación compila cada dependencia en orden cada vez que lo ejecutas. Piensas en agregar algo de lógica para detectar qué partes deben recompilarse, pero eso suena demasiado complejo y propenso a errores para una secuencia de comandos. O bien, piensas en especificar qué partes se deben volver a compilar cada vez, pero vuelves al punto de partida.

  • Buenas noticias: ¡Es hora de lanzar una versión! Será mejor que averigües todos los argumentos que debes pasar al comando jar para realizar la compilación final. Y recuerda cómo subirlo y enviarlo al repositorio central. Además, compila y envía las actualizaciones de la documentación, y envía una notificación a los usuarios. Mmm, tal vez esto requiera otra secuencia de comandos…

  • ¡Desastre! Se bloquea tu disco duro y ahora debes recrear todo el sistema. Fuiste lo suficientemente inteligente como para mantener todos tus archivos fuente en el control de versiones, pero ¿qué sucede con las bibliotecas que descargaste? ¿Puedes volver a encontrarlos todos y asegurarte de que sean la misma versión que cuando los descargaste por primera vez? Es probable que tus secuencias de comandos dependieran de que ciertas herramientas estuvieran instaladas en lugares específicos. ¿Puedes restablecer ese mismo entorno para que las secuencias de comandos vuelvan a funcionar? ¿Qué sucede con todas esas variables de entorno que configuraste hace mucho tiempo para que el compilador funcionara correctamente y luego olvidaste?

  • A pesar de los problemas, tu proyecto es lo suficientemente exitoso como para que puedas comenzar a contratar más ingenieros. Ahora te das cuenta de que no se necesita un desastre para que surjan los problemas anteriores: debes pasar por el mismo proceso doloroso de inicio cada vez que un nuevo desarrollador se une a tu equipo. Y, a pesar de tus esfuerzos, siempre habrá pequeñas diferencias en el sistema de cada persona. Con frecuencia, lo que funciona en la computadora de una persona no funciona en la de otra, y cada vez se necesitan algunas horas de depuración de rutas de herramientas o versiones de bibliotecas para determinar dónde está la diferencia.

  • Decides que necesitas automatizar tu sistema de compilación. En teoría, esto es tan simple como conseguir una computadora nueva y configurarla para que ejecute tu secuencia de comandos de compilación todas las noches con cron. Aún debes completar el doloroso proceso de configuración, pero ahora no tienes el beneficio de un cerebro humano que pueda detectar y resolver problemas menores. Ahora, cada mañana, cuando llegas, ves que la compilación de la noche anterior falló porque ayer un desarrollador hizo un cambio que funcionó en su sistema, pero no en el sistema de compilación automatizado. Cada vez es una solución simple, pero sucede con tanta frecuencia que terminas dedicando mucho tiempo cada día a descubrir y aplicar estas soluciones simples.

  • Las compilaciones se vuelven cada vez más lentas a medida que crece el proyecto. Un día, mientras esperas que se complete una compilación, miras con tristeza el escritorio inactivo de tu compañero de trabajo, que está de vacaciones, y deseas que hubiera una manera de aprovechar toda esa potencia de procesamiento desperdiciada.

Te encontraste con un problema clásico de escala. Para un solo desarrollador que trabaja en un máximo de un par de cientos de líneas de código durante un máximo de una o dos semanas (que podría haber sido toda la experiencia hasta el momento de un desarrollador junior que acaba de graduarse de la universidad), un compilador es todo lo que necesita. Las secuencias de comandos pueden llevarte un poco más lejos. Sin embargo, en cuanto necesitas coordinar a varios desarrolladores y sus máquinas, incluso un script de compilación perfecto no es suficiente, ya que resulta muy difícil tener en cuenta las pequeñas diferencias en esas máquinas. En este punto, este enfoque simple deja de funcionar y es hora de invertir en un sistema de compilación real.