En esta página, se explica qué son los sistemas de compilación, qué hacen, por qué deberías usar un sistema de compilación y por qué los compiladores y las secuencias de comandos de compilación no son la mejor opción a medida que tu organización comienza a crecer. Está destinada 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 son solo 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 directamente por los ingenieros.
¿No puedo usar un compilador?
Es posible que la necesidad de un sistema de compilación no sea 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 que todo el código fuente esté en
el mismo directorio, un comando como este funciona bien:
javac *.javaEsto le indica al compilador de Java que tome todos los archivos fuente de Java en el directorio actual y los convierta en un archivo de clase binario. En el caso más simple, esto es todo lo que necesitas.
Sin embargo, en cuanto se expande el código, comienzan las complicaciones. javac es lo suficientemente inteligente como para buscar en los subdirectorios del directorio actual para encontrar 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 correcto, posiblemente con 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 tedioso y propenso a errores rápidamente.
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
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 lo suficientemente simple como para que puedas compilarlo con solo 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 de shell simples que se encargan de compilar elementos en el orden correcto. Esto ayuda por 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 pasar casi el mismo tiempo trabajando en tus secuencias de comandos de compilación que en el código real. La depuración de secuencias de comandos de shell es dolorosa, con más y más soluciones alternativas superpuestas.
Es lento. Para asegurarte de que no dependas accidentalmente de bibliotecas obsoletas, tu secuencia de comandos de compilación compila cada dependencia en orden cada vez que la ejecutas. Piensas en agregar algo de lógica para detectar qué partes deben volver a compilarse, pero eso suena muy complejo y propenso a errores para una secuencia de comandos. O bien, piensas en especificar qué partes deben volver a compilarse cada vez, pero luego vuelves al punto de partida.
Buenas noticias: Es hora de un lanzamiento. Es 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 documentación, y envía una notificación a los usuarios. Hmm, quizás esto requiera otra secuencia de comandos...
¡Desastre! Se bloquea tu disco duro y ahora debes volver a crear todo el sistema. Fuiste lo suficientemente inteligente como para mantener todos tus archivos fuente en el control de versión, pero ¿qué sucede con las bibliotecas que descargaste? ¿Puedes volver a encontrarlas todas y asegurarte de que sean la misma versión que cuando las descargaste por primera vez ? Es probable que tus secuencias de comandos dependan de que se instalen herramientas específicas 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 funcione 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 de bootstrapping doloroso cada vez que un nuevo desarrollador se une a tu equipo. Y a pesar de tus mejores esfuerzos, aún existen pequeñas diferencias en el sistema de cada persona. Con frecuencia, lo que funciona en la máquina de una persona no funciona en la de otra, y cada vez se necesitan unas horas de depuración de rutas de herramientas o versiones de bibliotecas para averiguar dónde está la diferencia.
Decides que necesitas automatizar tu sistema de compilación. En teoría, esto es tan simple como obtener una computadora nueva y configurarla para que ejecute tu secuencia de comandos de compilación todas las noches con cron. Aún debes pasar por el doloroso proceso de configuración, pero ahora no tienes el beneficio de que un cerebro humano pueda detectar y resolver problemas menores. Ahora, todas las mañanas, cuando llegas , ves que la compilación de la noche anterior falló porque ayer un desarrollador realizó 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 pasando mucho tiempo cada día descubriendo y aplicando 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 haya 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 doscientas 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 necesitas. Las secuencias de comandos pueden llevarte un poco más lejos. Sin embargo, en cuanto necesites coordinar a varios desarrolladores y sus máquinas, incluso una secuencia de comandos de compilación perfecta no es suficiente porque se vuelve muy difícil tener en cuenta las pequeñas diferencias en esas máquinas. En este punto, este enfoque simple se descompone y es hora de invertir en un sistema de compilación real.