Kevlin Henney y yo discutimos recientemente si la generación automatizada de código, utilizando alguna versión futura de GitHub Copilot o similar, podría alguna vez reemplazar los lenguajes de nivel superior. Específicamente, ¿podría ChatGPT N (para N grande) abandonar el juego de generar código en un lenguaje de alto nivel como Python y producir código de máquina ejecutable directamente, como lo hacen los compiladores hoy en día? En realidad no es una cuestión académica. A medida que los asistentes de codificación se vuelven más precisos, parece probable asumir que eventualmente dejarán de ser “asistentes” y asumirán el trabajo de escribir código. Ése será un gran cambio para los programadores profesionales, aunque escribir código es una pequeña parte de lo que realmente hacen los programadores. Hasta cierto punto, está sucediendo ahora: el “Análisis de datos avanzado” de ChatGPT 4 puede generar código en Python, ejecutarlo en una zona de pruebas, recopilar mensajes de error e intentar depurarlo. Bard de Google tiene capacidades similares. Python es un lenguaje interpretado, por lo que no hay código de máquina, pero no hay razón para que este bucle no pueda incorporar un compilador de C o C++. Aprende más rápido. Excavar más hondo. Ver más lejos. Este tipo de cambio ha ocurrido antes: en los primeros días de la informática, los programadores “escribían” programas conectando cables, luego alternando números binarios, luego escribiendo código en lenguaje ensamblador y finalmente (a fines de la década de 1950) usando la programación inicial. lenguajes como COBOL (1959) y FORTRAN (1957). Para las personas que programaban utilizando diagramas de circuitos e interruptores, estos primeros lenguajes parecían tan radicales como lo parece hoy la programación con IA generativa. COBOL fue, literalmente, uno de los primeros intentos de hacer que la programación fuera tan simple como escribir en inglés. Kevlin señaló que los lenguajes de nivel superior son un “depósito de determinismo” del que no podemos prescindir, al menos no todavía. Si bien un “depósito de determinismo” suena un poco malvado (siéntete libre de inventar tu propio nombre), es importante entender por qué es necesario. En casi todas las etapas de la historia de la programación ha habido un depósito de determinismo. Cuando los programadores escribían en lenguaje ensamblador, tenían que mirar los 1 y 0 binarios para ver exactamente qué estaba haciendo la computadora. Cuando los programadores escribieron en FORTRAN (o, en realidad, C), el depósito de determinismo ascendió: el código fuente expresaba lo que querían los programadores y dependía del compilador entregar las instrucciones correctas de la máquina. Sin embargo, el estado de este repositorio aún era inestable. Los primeros compiladores no eran tan confiables como esperábamos. Tenían errores, especialmente si estaban optimizando su código (¿la optimización de los compiladores era un precursor de la IA?). La portabilidad era, en el mejor de los casos, problemática: cada proveedor tenía su propio compilador, con sus propias peculiaridades y sus propias extensiones. La Asamblea seguía siendo el “tribunal de último recurso” para determinar por qué su programa no funcionó. El depósito de determinismo sólo era efectivo para un único proveedor, computadora y sistema operativo.1 La necesidad de hacer que los lenguajes de nivel superior fueran deterministas en todas las plataformas informáticas impulsó el desarrollo de estándares y especificaciones de lenguajes. Hoy en día, muy pocas personas necesitan saber ensamblador. Necesita conocer el ensamblador para algunas situaciones difíciles al escribir controladores de dispositivos o para trabajar con algunos rincones oscuros del kernel del sistema operativo, y eso es todo. Pero si bien la forma en que programamos ha cambiado, la estructura de la programación no. Especialmente con herramientas como ChatGPT y Bard, todavía necesitamos un depósito de determinismo, pero ese depósito ya no es lenguaje ensamblador. Con C o Python, puedes leer un programa y entender exactamente lo que hace. Si el programa se comporta de manera inesperada, es mucho más probable que hayas entendido mal algún rincón de la especificación del lenguaje que que el compilador de C o el intérprete de Python se hayan equivocado. Y eso es importante: eso es lo que nos permite depurar con éxito. El código fuente nos dice exactamente qué está haciendo la computadora, en un nivel razonable de abstracción. Si no hace lo que queremos, podemos analizar el código y corregirlo. Esto puede requerir releer a Kernighan y Ritchie, pero es un problema manejable y bien comprendido. Ya no tenemos que mirar el lenguaje de máquina, y eso es algo muy bueno, porque con el reordenamiento de instrucciones, la ejecución especulativa y largos canales, entender un programa a nivel de máquina es mucho más difícil que en los años 1960 y 1970. . Necesitamos esa capa de abstracción. Pero esa capa de abstracción también debe ser determinista. Debe ser completamente predecible. Debe comportarse de la misma manera cada vez que compila y ejecuta el programa. ¿Por qué necesitamos que la capa de abstracción sea determinista? Porque necesitamos una declaración confiable de exactamente lo que hace el software. Toda la informática, incluida la IA, se basa en la capacidad de las computadoras para hacer algo de manera confiable y repetida, millones, miles de millones o incluso billones de veces. Si no sabe exactamente qué hace el software (o si podría hacer algo diferente la próxima vez que lo compile), no podrá crear un negocio en torno a él. Ciertamente no puedes mantenerlo, ampliarlo o agregar nuevas funciones si cambia cada vez que lo tocas, ni tampoco puedes depurarlo. La generación de código automatizada aún no tiene el tipo de confiabilidad que esperamos de la programación tradicional; Simon Willison llama a esto «desarrollo basado en vibraciones». Todavía dependemos de los humanos para probar y corregir los errores. Más concretamente: es probable que genere código muchas veces en el camino hacia una solución; No es probable que tome los resultados de su primer mensaje y salte directamente a la depuración, como tampoco es probable que escriba un programa complejo en Python y lo haga bien la primera vez. Escribir indicaciones para cualquier sistema de software importante no es trivial; Las indicaciones pueden ser muy largas y se necesitan varios intentos para hacerlo bien. Con los modelos actuales, cada vez que generas código, es probable que obtengas algo diferente. (Bard incluso le ofrece varias alternativas para elegir). El proceso no es repetible. ¿Cómo entiendes lo que hace el programa si es un programa diferente cada vez que lo generas y lo pruebas? ¿Cómo puede saber si está avanzando hacia una solución si la próxima versión del programa puede ser completamente diferente a la anterior? Es tentador pensar que esta variación es controlable estableciendo una variable como la “temperatura” de GPT-4 en 0; La “temperatura” controla la cantidad de variación (u originalidad o imprevisibilidad) entre las respuestas. Pero eso no resuelve el problema. La temperatura sólo funciona dentro de unos límites, y uno de esos límites es que la indicación debe permanecer constante. Cambie el mensaje para ayudar a la IA a generar código correcto o bien diseñado y estará fuera de esos límites. Otro límite es que el modelo en sí no puede cambiar, pero los modelos cambian todo el tiempo y esos cambios no están bajo el control del programador. Todos los modelos se actualizan eventualmente y no hay garantía de que el código producido permanezca igual en todas las actualizaciones del modelo. Es probable que un modelo actualizado produzca un código fuente completamente diferente. Ese código fuente deberá entenderse (y depurarse) en sus propios términos. Por lo tanto, el mensaje del lenguaje natural no puede ser el depósito del determinismo. Esto no significa que el código generado por IA no sea útil; puede proporcionar un buen punto de partida para trabajar. Pero en algún momento, los programadores necesitan poder reproducir y razonar sobre los errores: ese es el punto en el que se necesita repetibilidad y no se pueden tolerar sorpresas. También en ese punto, los programadores tendrán que abstenerse de regenerar el código de alto nivel desde el mensaje en lenguaje natural. La IA está creando efectivamente un primer borrador, y eso puede (o no) ahorrarle esfuerzo en comparación con comenzar desde una pantalla en blanco. Agregar funciones para pasar de la versión 1.0 a la 2.0 plantea un problema similar. Incluso las ventanas de contexto más grandes no pueden contener un sistema de software completo, por lo que es necesario trabajar con un archivo fuente a la vez, exactamente como trabajamos ahora, pero nuevamente, con el código fuente como depósito del determinismo. Además, es difícil decirle a un modelo de lenguaje qué se puede cambiar y qué no se debe modificar: “modificar sólo este bucle, pero no el resto del archivo” puede funcionar o no. Este argumento no se aplica a asistentes de codificación como GitHub Copilot. Copiloto tiene un nombre acertado: es un asistente del piloto, no el piloto. Puede decirle con precisión qué quiere que se haga y dónde. Cuando usas ChatGPT o Bard para escribir código, no eres el piloto ni el copiloto; eres el pasajero. Puedes decirle a un piloto que te lleve a Nueva York, pero a partir de ese momento, el piloto tiene el control. ¿Será alguna vez la IA generativa lo suficientemente buena como para saltarse los lenguajes de alto nivel y generar código de máquina? ¿Puede un mensaje reemplazar el código en un lenguaje de alto nivel? Después de todo, ya estamos viendo un ecosistema de herramientas que tiene repositorios rápidos, sin duda con control de versiones. Es posible que la IA generativa con el tiempo pueda reemplazar los lenguajes de programación para las secuencias de comandos del día a día (“Genere un gráfico a partir de dos columnas de esta hoja de cálculo”). Pero para proyectos de programación más grandes, tenga en cuenta que parte del valor del lenguaje humano es su ambigüedad, y un lenguaje de programación es valioso precisamente porque no es ambiguo. A medida que la IA generativa penetre más en la programación, sin duda veremos dialectos estilizados de lenguajes humanos que tienen una semántica menos ambigua; esos dialectos pueden incluso estandarizarse y documentarse. Pero “dialectos estilizados con semántica menos ambigua” es en realidad sólo un nombre elegante para la ingeniería rápida, y si desea un control preciso sobre los resultados, la ingeniería rápida no es tan simple como parece. Todavía necesitamos un depósito de determinismo, una capa en la pila de programación donde no haya sorpresas, una capa que proporcione la palabra definitiva sobre lo que hará la computadora cuando se ejecute el código. La IA generativa no está a la altura de esa tarea. Al menos no todavía. Si estuvo en la industria informática en la década de 1980, tal vez recuerde la necesidad de “reproducir el comportamiento de VAX/VMS FORTRAN error por error”.

Source link