¿Pueden las IAs Generativas reemplazar a los programadores?
TL;DR: solo en tareas muy básicas, pero pueden ser un apoyo de gran utilidad
Desde la aparición de varias Inteligencias Artificiales Generativas como ChatGPT o Midjourney no hemos parado de sufrir un bombardeo continuo de noticias con titulares de esta guisa:
🔥 “El fin de los dibujantes” / “El fin de los escritores” / “El fin de [PROFESIÓN QUE SEA]”
🔥 “Las empresas que no utilicen IA desaparecerán” / “La IA Generativa multiplica x10 la efectividad de las empresas”
🔥 “La IA terminará con todos los trabajos”
Como alguien que lleva ya casi 20 años trabajando en este mundo, esta clase de afirmaciones me parecen desproporcionadas. Y probablemente interesadas, dada la reciente aparición de gran cantidad de empresas “basadas en IA”, de “influencers de la IA”, y de fondos de inversión que están interesados en inflar las expectativas todo lo posible.
Por supuesto, soy un total convencido de que la IA es una tecnología extremadamente útil, y la evolución tanto científica como empresarial que ha experimentado en los últimos años ha sido vertiginosa. Tanto ha sido así, que si hace 5 años me hubieran dicho que a día de hoy tendríamos IAs que generan imágenes fotorrealistas, o grandes modelos de lenguaje (LLMs, Large Language Models) con los que puedes entablar un diálogo sobre prácticamente cualquier tema, me lo habría tomado a broma. No habría estado solo: muchos expertos de renombre mundial en el campo han reconocido que tampoco habían previsto esta evolución.
¿A qué se deben percepciones tan dispares? Tal vez este sea un caso similar al efecto Dunning-Kruger: las personas con poco conocimiento en un ámbito tienden a sobrestimar sus habilidades, y por el contrario, los expertos tienden a infraestimarlas. Saltando de las autopercepciones a la percepción sobre las capacidades de la IA o de la tecnología en general, los neófitos suelen quedar fascinados por las posibilidades que esta ofrece, teniendo así expectativas demasiado altas. En cambio, los expertos técnicos en el campo tienden a centrarse en las limitaciones y los problemas aún por resolver, y por ello a minusvalorar la aplicabilidad de la tecnología.

Parece por tanto que todos tenemos sesgos a la hora de evaluar el impacto de estas tecnologías. ¿Cómo podemos entonces valorarla de manera objetiva? No hace falta irnos muy lejos: basta con usar el método científico, precisamente el mismo que ha permitido desarrollar estas tecnologías.
De modo que en este post me planteo comprobar experimentalmente hasta qué punto pueden las últimas IAs Generativas reemplazar un trabajo cognitivo complejo. Concretamente, el trabajo de un desarrollador de software. El desarrollo de software es un trabajo fundamental en la creación de las propias herramientas de IA, y una actividad a la que me he venido dedicando muchos años. Evaluar el grado de automatización de una de las tareas de mi propio trabajo me parece una investigación de gran interés para mi futuro inmediato. 😜
¿Cómo medir capacidades en desarrollo de software?
El desarrollo de software es un campo muy amplio, que incluye múltiples facetas. Aunque se comparten conocimientos y habilidades de base, es muy diferente programar una aplicación web, un algoritmo de IA, o un videojuego. No solo por la diferencia existente en lenguajes de programación, sino también por la diversidad de herramientas y estándares empleados en para cada dominio. Además, desarrollar una solución software completa implica también la capacidad de diseñar y comprender sistemas formados por varios módulos, de interactuar con los demás colaboradores del proyecto, y de entender los requisitos del usuario y trasladarlos a código.
Por tanto aquí nos limitaremos a medir solo una faceta concreta del desarrollo de software: resolver ejercicios de programación, también conocidos como katas. En estos ejercicios se presenta al programador una descripción de una funcionalidad concreta que debe implementar, como por ejemplo el crear una función que indique si un número dado es par o impar. El programador entonces debe desarrollar un código que aborde esa funcionalidad, siguiendo unas indicaciones sobre el lenguaje de programación a usar y el formato a seguir.
La ventaja de esta clase de ejercicios es que es posible comprobar de manera automática si el código realizado es correcto o no. El diseñador de la kata crea una serie de tests que ponen a prueba la solución propuesta por el programador, verificando en una variedad de casos si las respuestas producidas por ese código son las esperadas. Por ejemplo, para validar que el programador ha hecho bien su trabajo de crear un código que calcule la paridad de un número, basta con invocar ese código con diferentes números de los que ya se conoce su paridad (2-par, 13-impar, 46-par, …) y confirmar que en todos los casos nos devuelve el resultado esperado. Esta metodología permite juzgar de manera objetiva si el trabajo de desarrollo se ha realizado correctamente.
Una web que implementa todo este sistema de katas de manera muy interesante, y que a mí personalmente me gusta usar para practicar, es CodeWars.
Además de contener miles de katas creadas por su comunidad y en todo tipo de lenguajes de programación, CodeWars también incluye un sistema de clasificación de las katas por dificultad, en la forma de kyus, asemejando los niveles de experiencia de un arte marcial. Las katas están catalogadas desde el kyu 8 (más fácil) hasta el kyu 1 (mas difícil):
Kyu 8 y 7: ejercicios básicos, que requieren conocer los fundamentos de un lenguaje de programación y resolver tareas sencillas con ellos. Ejemplos: calcular si un número es par u ordenar los dígitos que representan un número. Desafiantes para alguien que está aprendiendo a programar por primera vez, pero triviales para un desarrollador experimentado.
Kyu 6 y 5: ejercicios intermedios, para los que es necesario conocer en más detalle el lenguaje de programación, y haber estudiado estructuras de datos y algoritmos básicos.
Kyu 4 y 3: ejercicios avanzados, en su mayoría requiriendo conocimientos de algoritmos más complejos, de fundamentos matemáticos, o de la implementación de varias subrutinas.
Kyu 2 y 1: ejercicios de alta complejidad. Puede requerir implementar la lógica interna de lo que podría ser una aplicación completa, como un jugador perfecto de Buscaminas, o un sistema de diferenciación simbólica. En otras ocasiones se requiere de un desarrollo matemático no evidente, o de la aplicación de técnicas de optimización de código para cumplir con requisitos estrictos de tiempos de ejecución, como en el cálculo del área de la intersección de dos círculos.
Analizando las estadísticas de aproximadamente 8000 katas de CodeWars, podemos confirmar que en términos generales el kyu está correlacionado con la dificultad real: las katas más complejas son completadas con éxito por una proporción menor de los usuarios que las comienzan.

Con esta información tenemos una base sobre la que evaluar si una IA Generativa es capaz de rendir a un nivel comparable al de un desarrollador de software. Ahora tenemos que poner a la IA a trabajar.
Una IA para resolver katas
Para este estudio he decidido hacer uso de GPT-4o-mini, dado que, a fecha de escritura de este post, este modelo de lenguaje se encuentra posicionado el #3 para tareas generales en el LMSYS Chatbot Arena Leaderboard (un ranking de referencia en LLMs), y el #2 para tareas de programación. Aunque el modelo completo (GPT-4o) demuestra mejor rendimiento en este ranking, el hecho de la versión mini sea ~30 veces más barata la convierte en una solución más práctica.
Por supuesto, un modelo de lenguaje no puede aplicarse a esta tarea por sí mismo. Es por ello que he desarrollado una serie de bots que interactúan entre CodeWars y la API de OpenAI para realizar la tarea.1

Toda la implementación del sistema se ha hecho en python, empleando Selenium para la creación de los bots que interactúan con CodeWars.2
Los prompts que se utilizan para solicitar al modelo de lenguaje que resuelva la kata son los siguientes:
System prompt (indicaciones generales del comportamiento del LLM)
You are an expert {language} programmer solving a code exercise. Pay close attention to the instructions, and generate an answer in {language}, following the same function header as provided. The generated code must run as fast as possible in order to avoid timeouts at tests time. A sample of unit tests for the function to implement will also be provided, which you do not need to replicate in the generated output. Do not generate any text explanation or examples, just generate the {language} code with the solution.
User prompt (tarea concreta a realizar)
-----
Exercise description
-----
{description}
-----
Solution template
-----
{solution_template}
-----
Reference unit tests
-----
{unit_tests}
En los prompts se indica tanto el lenguaje de programación a utilizar, como la descripción de la kata, la plantilla a seguir para la solución, y los tests de ejemplo que el desarrollador puede ver. De esta manera, tanto la IA como un humano parten de la misma información para resolver el problema.
LLM vs humanos
Tras ejecutar el sistema de bots sobre ~15.000 variantes katas en diferentes lenguajes de programación, este es el nivel de rendimiento conseguido, en comparación con los desarrolladores humanos.

Varios hechos llaman la atención:
El LLM es mejor que los humanos resolviendo tareas fáciles (kyu 8 y 7).
El rendimiento de humanos y LLMs es similar al resolver tareas intermedias (kyu 6 y 5), e incluso las primeras tareas avanzadas (kyu 4)
Al llegar a tareas de kyu 3 el rendimiento de los LLMs es significativamente peor. Y los ejercicios de más alta complejidad (kyu 2 y kyu 1) son un fracaso absoluto: el LLM no consigue resolver ninguno de ellos.
Desglose por lenguajes de programación
Podemos profundizar en el análisis separando el rendimiento del LLM según el lenguaje de programación utilizado.

Es destacable que el rendimiento depende significativamente del lenguaje de programación utilizado.
El LLM se desenvuelve mejor en lenguajes con un uso muy extendido: javascript y python son los dos lenguajes generalistas más utilizados a día de hoy en GitHub, como puede comprobarse en sus datos oficiales. Además, en estos lenguajes las soluciones propuestas para los ejercicios más difíciles no parecen ser totalmente incorrectas, sino que en muchas ocasiones fallan por no estar lo suficientemente optimizadas (Timeout).
Incluso en lenguajes con menor uso, como C (#8) o R (#26), el rendimiento se mantiene bastante bien, aunque en estos lenguajes el LLM no consigue resolver ninguna de las katas de kyu 3.
Aunque Julia es un lenguaje aún poco utilizado (no aparece en el top 50 del ranking de GitHub), el LLM lo maneja razonablemente bien, consiguiendo un rendimiento más bajo que para C o R en ejercicios intermedios o avanzados, pero bueno en ejercicios básicos3. Algo similar ocurre para Solidity (#36).
Cuando pasamos a lenguajes históricos como Fortran o COBOL, el rendimiento cae en picado. COBOL en especial muestra unos resultados catastróficos.
Para condensar toda esta información en una única métrica que resuma la efectividad del LLM programando en un lenguaje concreto, podemos basarnos en el CodeWars score. Se trata de un esquema que asigna mayor puntuación a las katas de mayor nivel, siguiendo la progresión: (kyu 8) 2, 3, 8, 21, 55, 149, 404, 1097 (kyu 1). Usando esto, podemos emplear la siguiente fórmula de puntuación:
Donde si es el score de CodeWars para las katas de kyu i, rli es la proporción de katas de kyu i resueltas en el lenguaje de programación l, y pl es la puntuación final para el lenguaje de programación l.
Con esto obtenemos la siguiente comparativa de rendimientos:

Python resulta ser el lenguaje en el que mejor programa el LLM. No obstante, el score de 36.1 indica que aunque está lejos de poder aportar soluciones válidas de forma consistente para ejercicios avanzados: un sistema que resolviera todas las katas hasta kyu 4 o superior obtendría 87 puntos.
Explicando las diferencias por lenguaje
¿Qué es lo que motiva que el LLM tenga mejor rendimiento en unos lenguajes que en otros? Ya ha quedado patente en varias investigaciones (de las que hablaré en otro post) que los LLMs no pueden generar respuestas que estén muy lejos de sus datos de entrenamiento. Por tanto, cabría esperar que si un LLM programa bien en un lenguaje es porque se ha entrenado con gran cantidad de código escrito en ese lenguaje.
Los datos de entrenamiento que se han usado para los modelos GPT no son públicamente conocidos, pero una hipótesis bastante razonable es que se haya empleado todo el código disponible en GitHub. No he encontrado estadísticas de líneas de código totales almacenadas en esta comunidad, pero sí estadísticas de número de pushes a repositorios, según idioma. Podemos entonces generar el siguiente análisis:

La correlación es bastante clara: los lenguajes con más código disponible para entrenamiento son en los que el LLM es capaz de programar mejor. Esto es una buena noticia para los programadores que trabajan en los lenguajes más utilizados, pero una decepción para aquellos proyectos que se plantean usar la IA para mantener o adaptar las grandes bases de código de COBOL y Fortran que aún existen en sistemas productivos legacy.
El peso de la historia
La variabilidad en las habilidades del LLM no se queda únicamente en la dificultad de la tarea o el lenguaje utilizado. Sorprendentemente, la fecha de publicación de la kata también tiene un impacto en el rendimiento, tanto en el LLM como en los humanos:

Las katas de mayor antigüedad son resueltas con mayor facilidad que las katas más recientes. Esto afecta al score de los humanos, tanto de manera global como si excluímos las katas más complejas (nos quedamos solo con kyus ≥ 3) o nos centramos en las básicas e intermedias (kyus ≥ 5). Pero afecta de manera aún más pronunciada al LLM: inicialmente muestra un score superior al de los humanos si ignoramos los ejercicios de alta complejidad, pero acaba degenerando en niveles de score peores que los obtenidos por humanos en ejercicios básicos e intermedios.
Hay dos hipótesis que pueden explicar este fenómeno:
El criterio para seleccionar el kyu de una kata ha cambiado, y una kata con un cierto kyu K en 2024 es más difícil de resolver que una kata de 2013 con un mismo kyu K.
Con el tiempo se van filtrado las soluciones de las katas, lo que permite que los humanos puedan copiar esas soluciones, y que los LLMs también las conozcan por estar entre sus datos de entrenamiento.
Probablemente ambas hipótesis sean correctas. Pero conociendo cómo funcionan los LLMs y la dependencia tan fuerte que tienen de sus datos de entrenamiento, tiendo a pensar que la segunda hipótesis es la que más influencia tiene. Basta una búsqueda rápida en GitHub de “codewars” para encontrar ~38500 repositorios públicos donde se han publicado soluciones.
Análisis global
Finalmente, aporto aquí un análisis global de todos los elementos que pueden estar impactando en la capacidad del LLM de resolver las katas:
Dificultad (kyu).
Fecha de publicación.
Usuarios que han completado la kata, en términos absolutos y en porcentaje; también estos mismos datos circunscritos al lenguaje concreto utilizado en la solución.
Lenguaje en el que se intenta resolver, y estadísticas de GitHub asociadas: número de pushes en los últimos años y posición en el ranking de lenguajes más usados.
Tras montar una tabla de datos con esta información para cada kata y lenguaje, he entrenado un modelo de aprendizaje automático sencillo (SVM lineal) para predecir si el LLM será capaz de resolver la kata o no. Este modelo obtiene un acierto del 75% en una validación cruzada de 5 hojas. No se obtienen resultados mejores al usar un modelo más complejo (XGBoost), por lo que el modelo lineal parece un buen ajuste.
Una vez obtenido el modelo, paso a realizar un análisis de sus coeficientes de SHAP, teniendo en consideración posibles correlaciones entre las variables explicativas.

Los factores más relevantes para el éxito del LLM incluyen varias variables que codifican cuántos usuarios han completado ya la kata, así como su dificultad (rank). Con menor impacto aparece el número de días que han pasado desde que se publicó la kata, y finalmente tenemos todas las variables relacionadas con el lenguaje utilizado. Estos resultados refuerzan los análisis descriptivos presentados arriba.
Conclusiones
A pesar de lo que nos pueda parecer, las IAs Generativas y los LLMs en concreto no son máquinas con capacidad de razonamiento. Responden a nuestras peticiones en base a recuperar consultas similares vistas durante su entrenamiento, y elaboran una respuesta que es una mezcla de todas ellas. Esto los convierte en buscadores generativos de una tremenda potencia, pero también pueden producir fracasos si nuestra petición está muy lejos de lo que han aprendido.
En este estudio hemos visto que a la hora de programar con éxito, un LLM está fuertemente influenciado tanto por la dificultad de la tarea, como por la popularidad del lenguaje de programación utilizado, y muy probablemente por la existencia de soluciones similares en la web. Por tanto, sobre los LLMs aplicados a programación podemos decir que:
Son muy útiles para resolver tareas sencillas que muchos otros ya han resuelto. En este sentido son una herramienta valiosa y complementaria a la clásica búsqueda online o a Stack Overflow, acelerando los tiempos de desarrollo y aprendizaje.
No pueden generar soluciones válidas para problemas complejos, o para los que no existen soluciones online. Pueden aportar ideas, pero debemos ser muy críticos con ellas, ya que con alta probabilidad serán parcial o totalmente incorrectas.
No funcionan bien para lenguajes poco populares o antiguos. Esto es un batacazo para los proyectos que pretenden mantener bases de código legacy.
Así que, retomando la pregunta que abre este post, “¿pueden las IAs generativas reemplazar a los programadores?”, podemos decir que no son un reemplazo. Aunque evidentemente son una herramienta que acelera parte del desarrollo, como ya ocurrió en épocas pasadas con la aparición de internet, los buscadores web, Stack Overflow o GitHub.
¿Puede que esto cambie drásticamente en el futuro? Tal vez. Pero no será con la tecnología de IA que conocemos a día de hoy, y el día que eso ocurra estaríamos tratando con un nuevo tipo de Inteligencia Artificial que sea realmente general, y sobre la que tendremos que plantearnos otra serie de preocupaciones de mayor calado.
Leer más y citas
Los detalles completos de los experimentos realizados se encuentran disponibles en formato paper en la plataforma arxiv: An evaluation of LLM code generation capabilities through graded exercises.
Si utilizas imágenes o contenido de este artículo te ruego que cites el paper como
An evaluation of LLM code generation capabilities through graded exercises. Álvaro Barbero Jiménez. arXiv preprint arXiv:2410.16292. https://arxiv.org/abs/2410.16292
Agradecimientos al Instituto de Ingeniería del Conocimiento por proveer de créditos de OpenAI para costear estos experimentos.
El código de conducta de CodeWars prohíbe el uso de sistemas de IA, para resolver problemas de forma automatizada. Por ello, estos bots emplean usuarios de CodeWars que han sido creados únicamente para esta tarea, y que después han sido eliminados, con el fin de no impactar en el ranking de usuarios reales que usan esta plataforma para medir sus habilidades de programación. De igual modo, todo el crawling se ha hecho de forma respetuosa para no provocar problemas de servicio.
El valor anómalo de 100% Timeout para kyu 1 en Julia se debe a que solo existe una kata de kyu 1 abordable en este lenguaje, para la cual la solución LLM obtiene un Timeout. En vista del resto de resultados para este lenguaje, sería improbable que se mantuviera este resultado en otras katas del mismo nivel.
Imagen de cabecera del post creada usando el modelo ReV Animated 1.2.1.