El artículo explora la pregunta de si los compiladores son deterministas, un tema crucial en el desarrollo de software, especialmente con la creciente integración de modelos de lenguaje grandes (LLMs). La respuesta, según el autor, depende de si se considera desde una perspectiva teórica (ciencia de la computación) o práctica (ingeniería).
¿Qué significa que un compilador sea determinista? En esencia, un compilador determinista es una función que, dada la misma entrada (código fuente, flags, entorno, etc.), siempre produce la misma salida (código objeto). Formalmente, la salida de un compilador (el artefacto final) depende de una serie de factores: el código fuente, las flags de compilación, el propio binario del compilador, el enlazador, las bibliotecas en tiempo de ejecución, variables de entorno, el sistema de archivos, la configuración regional, la hora del sistema, el comportamiento del kernel y la programación de la concurrencia del hardware.
El problema de la no reproducibilidad: Aunque teóricamente los compiladores deberían ser deterministas, en la práctica, la no reproducibilidad es común. Esto se debe a que los equipos de desarrollo a menudo solo controlan el código fuente y las flags, considerando el resto como “ruido”. Este “ruido” puede incluir cambios sutiles en la asignación de registros, el comportamiento de las fases del compilador o la disposición de las secciones de código, que resultan en código objeto diferente aunque la intención del código fuente sea la misma. El autor ilustra esto con ejemplos históricos, como el GCC bug 18574, donde la inestabilidad en el hash de punteros afectaba el orden de recorrido y la coalescencia de SSA.
Reproducibilidad y el esfuerzo de Debian: El movimiento de compilaciones reproducibles, impulsado por Debian a partir de 2013, busca garantizar que la misma fuente y las mismas instrucciones de compilación produzcan artefactos idénticos, bit a bit. Para lograrlo, se utilizan técnicas como establecer la zona horaria a UTC, la configuración regional a C, fijar la variable de entorno SOURCE_DATE_EPOCH, y utilizar flags de compilación como -ffile-prefix-map y -fdebug-prefix-map.
LLMs y el futuro del desarrollo: El artículo concluye que, aunque los LLMs pueden ayudar a identificar y corregir errores en el código, es crucial mantener “puertas de verificación” deterministas para el código generado. La ingeniería no depende de la inteligencia perfecta, sino de interfaces controladas, oráculos de prueba reproducibles y observabilidad. El autor enfatiza que, aunque los sistemas probabilísticos pueden ofrecer mejores resultados operacionales, la verificación determinista sigue siendo esencial, especialmente en un entorno donde la fiabilidad y la seguridad son primordiales. En última instancia, el artículo aboga por un enfoque pragmático: usar las herramientas disponibles, pero construir salvaguardias para mitigar los riesgos asociados.
