La combinación de TDD (Test-Driven Development) y los LLM
- TDD es una metodología de desarrollo en la que se escriben primero pruebas unitarias exhaustivas antes de empezar a programar
- Como las pruebas en la práctica cumplen el papel de especificación, cuando al final todas pasan se puede demostrar en cierta medida la corrección del código
- Tradicionalmente, TDD también ha recibido críticas por afectar la productividad o ser ineficiente
- Pero con la llegada de los LLM, el proceso de escribir pruebas y ajustar el código de forma iterativa se ha vuelto mucho más sencillo
Cómo uso normalmente los LLM
- He usado activamente herramientas como GitHub Copilot
- Los LLM son buenos para encontrar patrones repetitivos y autocompletar las siguientes líneas, pero a menudo les cuesta entender a fondo todo el problema y producir de una sola vez un módulo completo y bien cerrado
- Si se le da demasiado contexto al modelo para resolver un problema, es fácil que se desvíe del tema
- Si el trabajo se hace entregando solo partes de la información según haga falta (como la salida de errores), el modelo también resulta de gran ayuda para depurar
- He notado que se genera fricción al repetir el proceso de copiar y pegar entre el IDE, la terminal y la interfaz de chat
¿Se puede automatizar?
- Para automatizar este proceso, introduje directamente el concepto de event loop
- Si en el primer prompt se especifican la definición y la firma de la función a implementar, el modelo propone un borrador de las pruebas unitarias y del código
- Ese código se guarda en el directorio
sandbox y se ejecuta automáticamente go test
- Si las pruebas fallan, en el segundo prompt (iterativo) se envían juntos el código existente y los resultados de las pruebas (errores de compilación o información del fallo)
- Con base en eso, el modelo vuelve a proponer pruebas e implementación corregidas
- Este proceso se repite hasta que todas las pruebas pasen
- Este enfoque permite una mejora gradual sin acumular demasiado contexto
- El modelo puede fallar repetidamente en el mismo caso de prueba; en ese caso, una persona señala directamente la parte problemática y da pistas
- Hay que reconocer el problema de la “ausencia de vigilante”, donde se debe dudar de si las pruebas creadas por el LLM son lo bastante estrictas
- Existe la posibilidad de que el código y las pruebas compartan el mismo error o un diseño incompleto
- Por eso es importante que una persona refuerce además los casos de prueba
- Si hace falta, también se podrían experimentar con IA técnicas como mutation testing
Desarrollo basado en LLM y carga cognitiva (cognitive load)
- Al aplicar TDD junto con LLM, se espera que funcione no solo para problemas algorítmicos comunes, sino también en bases de código reales con dependencias
- Eso sí, la estructura del proyecto debe dividirse en unidades más pequeñas para mejorar la mantenibilidad, y cada directorio/paquete debe poder probarse de forma independiente
- Se recomienda separar cada paquete en definiciones de tipos principales (
shared.go), archivos a cargo de una lógica específica (x.go) y pruebas (x_test.go) para reducir la carga cognitiva
- En el proceso de usar IA, en vez de entregar todo el código al modelo cada vez, se seleccionan solo partes concretas para ayudarlo a concentrarse
- Esto aumenta la cobertura de pruebas y al mismo tiempo reduce el acoplamiento entre módulos, lo que también beneficia el mantenimiento a largo plazo
- Incluso en proyectos grandes, se apunta a una estructura que los divida en unidades pequeñas y claras, concentrando una lógica rica en cada unidad pero manteniendo el alcance al mínimo
Cierre
- Considerando la velocidad a la que avanza la IA, mañana mismo podría aparecer una nueva arquitectura que supere las limitaciones de los LLM
- Por eso, en lugar de refactorizar de golpe código legado masivo de más de 100 mil líneas, se recomienda explorar la combinación de TDD y LLM empezando por algo pequeño
- Se espera que la fusión de TDD y LLM pueda generar cambios positivos tanto en la generación automática de código como en la gestión de la calidad de las pruebas
5 comentarios
Me hace pensar mucho en qué tipo de pipeline estarán usando otros servicios de IA enfocados en desarrollo.
(Cuando veo cosas así,) siento que en cualquier momento van a insertar electrodos de estimulación eléctrica en el cerebro para crear un cerebro cibernético.
Parece buena idea incluir código de pruebas, pero no me parece que el programa que hizo esta persona tenga mucho mérito.
En cline o aider también se puede ejecutar desde la línea de comandos y recibir los resultados, así que, considerando la conveniencia, creo que sería mejor simplemente usar bien los prompts en esos programas.
El micro-agent hecho por Builder.io también sigue un enfoque parecido. https://github.com/BuilderIO/micro-agent Yo también he probado varias veces con LLM y TDD, pero también hay que hacer bien la abstracción, por ejemplo con un sistema de diseño. También es necesario tener bien definidos las convenciones y los patrones. Normalmente prefiero escribir yo mismo los casos de prueba. (¿Aunque sea en lenguaje humano?) Sobre todo, como también dice este artículo, hay que diseñar bien módulos con bajo acoplamiento y alta cohesión para poder meter el contexto dentro de una ventana de contexto limitada.
Aunque los LLM manejan bien el código de alcance pequeño, todavía se quedan cortos en el diseño general y la visión amplia,
pero combinarlo con TDD e ir mejorándolo poco a poco me parece una buena forma.