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

Informa un problema Ver código fuente

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 cuando tu organización comienza a escalar. Está dirigido a desarrolladores que no tienen mucha experiencia en un sistema de compilación.

¿Qué es un sistema de compilación?

En esencia, todos los sistemas de compilación tienen un propósito directo: transforman el código fuente que escriben los ingenieros en objetos binarios ejecutables que las máquinas pueden leer. Los sistemas de compilación no son solo para código creado por humanos; también permiten que las máquinas creen compilaciones de forma automática, ya sea para pruebas o versiones en producción. En una organización con miles de ingenieros, es común que la mayoría de las compilaciones se activen de forma automática en lugar de hacerlo directamente por los ingenieros.

¿No puedo usar un compilador?

Es posible que la necesidad de un sistema de compilación no sea obvia de inmediato. La mayoría de los ingenieros no usan un sistema de compilación mientras aprenden a programar: en la mayoría de los casos, se invocan herramientas como gcc o javac directamente desde la línea de comandos o el equivalente en un entorno de desarrollo integrado (IDE). Si todo el código fuente se encuentra en el mismo directorio, un comando como este funciona bien:

javac *.java

Esto le indica al compilador de Java que tome cada archivo de origen de Java del directorio actual y lo convierta en un archivo de clase binaria. 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 para buscar en los subdirectorios del directorio actual como para encontrar el código que deseas importar. Sin embargo, no tiene forma de encontrar el código almacenado en otras partes del sistema de archivos (quizás una biblioteca compartida por varios proyectos). También sabe cómo compilar código Java. Los sistemas grandes a menudo implican diferentes piezas escritas en una variedad de lenguajes de programación con web de dependencias entre ellas, lo que significa que ningún compilador para un solo lenguaje puede compilar todo el sistema.

Una vez que te ocupes del código de varios lenguajes o varias unidades de compilación, compilar código ya no es un proceso de un solo paso. Ahora debes evaluar de qué depende el código y compilar esas partes en el orden adecuado, posiblemente mediante el uso de un conjunto diferente de herramientas para cada pieza. Si cambian las dependencias, debes repetir este proceso para evitar depender de objetos binarios inactivos. Para una base de código de tamaño uniforme, este proceso se vuelve rápidamente tedioso y propenso a errores.

El compilador tampoco sabe nada sobre cómo manejar dependencias externas, como archivos JAR de terceros en Java. Sin un sistema de compilación, puedes administrar esto descargando la dependencia de Internet, pegá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?

Supón que tu proyecto de pasatiempo comienza de modo simple, por lo que puedes compilarlo solo con un compilador, pero comienzas a encontrar algunos de los problemas descritos antes. Quizás todavía 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 las cosas en el orden correcto. Esto ayuda durante un tiempo, pero pronto comienzas a tener incluso más problemas:

  • Se vuelve tedioso. A medida que el sistema se vuelve más complejo, comienzas a dedicar casi el tiempo necesario a trabajar en las secuencias de comandos de compilación y en el código real. La depuración de las secuencias de comandos de shell es complicada, ya que cada vez más trucos se superponen.

  • Es lento. Para asegurarte de que no dependías accidentalmente de las bibliotecas inactivas, la secuencia de comandos de compilación compilará todas las dependencias en orden cada vez que las ejecutes. Piensas en agregar lógica para detectar qué partes se deben volver a compilar, pero eso suena muy complejo y propenso a errores en una secuencia de comandos. También puedes especificar qué partes se deben volver a compilar cada vez, pero vuelves al cuadrado.

  • Buenas noticias: es hora del lanzamiento. Mejor, averigüe todos los argumentos que necesita pasar al comando jar para realizar su compilación final. Y recuerda cómo subirlo y enviarlo al repositorio central. Crea y envía las actualizaciones de la documentación, y envía una notificación a los usuarios. Mmm, quizás esto necesite otra secuencia de comandos...

  • Desastre. El disco duro falla y ahora debes volver a crear todo el sistema. Eres lo suficientemente inteligente para mantener todos tus archivos de origen en control de versión, pero ¿qué ocurre con esas bibliotecas que descargaste? ¿Puedes volver a encontrarlas y asegurarte de que tuvieran la misma versión que cuando las descargaste por primera vez? Es probable que tus secuencias de comandos dependan de la instalación de herramientas particulares en lugares particulares. ¿Puedes restablecer ese mismo entorno para que las secuencias de comandos vuelvan a funcionar? ¿Qué ocurre con todas esas variables de entorno que configuraste hace mucho tiempo para que el compilador funcione correctamente y luego te hayas olvidado?

  • A pesar de los problemas, tu proyecto tiene el éxito suficiente para comenzar a contratar a más ingenieros. Ahora te das cuenta de que no es necesario que ocurra un desastre para los problemas anteriores. Debes realizar el mismo proceso difícil de arranque cada vez que un desarrollador nuevo se una a tu equipo. A pesar de tus mejores esfuerzos, hay pequeñas diferencias en el sistema de cada persona. Con frecuencia, lo que funciona en la máquina de un usuario no funciona en otro y cada vez toma unas horas de depuración de rutas de acceso de herramientas o versiones de biblioteca para determinar dónde está la diferencia.

  • Decide que necesita automatizar su sistema de compilación. En teoría, esto es tan simple como obtener una computadora nueva y configurarla para ejecutar tu secuencia de comandos de compilación todas las noches mediante cron. Aún debes atravesar el doloroso proceso de configuración, pero ahora no tienes el beneficio de que el cerebro humano sea capaz de detectar y resolver problemas menores. Ahora, todas las mañanas cuando entras, ves que la compilación de anoche 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 frecuencia que descubres y aplicas muchas de ellas a diario.

  • Las compilaciones se vuelven cada vez más lentas a medida que el proyecto crece. Un día, mientras esperas a que se complete una compilación, miras con tristeza el escritorio inactivo de tu compañero de trabajo, que está de vacaciones, y desearías tener una forma de aprovechar todo ese poder de procesamiento desperdiciado.

Te encontraste con un problema de escala clásico. Para un único desarrollador que trabaja con un máximo de doscientas líneas de código durante una semana o dos (que podría haber sido toda la experiencia hasta el momento para un desarrollador júnior que acaba de graduarse de la universidad), todo lo que necesitas es un compilador. Las secuencias de comandos pueden te llevar un poco más lejos. Sin embargo, tan pronto como necesites coordinar entre varios desarrolladores y sus máquinas, incluso una secuencia de comandos de compilación perfecta no es suficiente, ya que se vuelve muy difícil dar cuenta de las pequeñas diferencias en esas máquinas. En este punto, este enfoque simple se desglosa y es hora de invertir en un sistema de compilación real.