1 puntos por GN⁺ 2024-02-25 | 1 comentarios | Compartir por WhatsApp

El nuevo generador de pruebas basado en LLM de Meta ofrece una mirada al futuro del desarrollo

  • Meta publicó un artículo titulado "Automated Unit Test Improvement using Large Language Models at Meta".
  • El artículo muestra cómo usar IA para acelerar el desarrollo y reducir los errores en el software.
  • Al integrar LLM en el flujo de trabajo de los desarrolladores, propone mejoras de software precisas y completas para mejorar la cobertura de código actual.

Puntos clave

  • TestGen-LLM usa el enfoque "Assured LLM-based Software Engineering" (Assured LLMSE).
  • Usa un enfoque de ensamble que genera mejoras de código con varios LLM, prompts e hiperparámetros, y selecciona la mejor mejora.
  • TestGen-LLM fue diseñado específicamente para mejorar pruebas existentes escritas por humanos.

Estadísticas

  • En la evaluación de productos Reels y Stories de Instagram, el 75% de los casos de prueba generados por TestGen-LLM compiló correctamente, el 57% pasó de forma confiable y el 25% aumentó la cobertura.
  • TestGen-LLM pudo mejorar el 10% de todas las clases a las que se aplicó, y los desarrolladores aceptaron el 73% de las mejoras de pruebas para llevarlas a producción.
  • En el "test-a-thon" donde ingenieros de Meta generaron pruebas para aumentar la cobertura de pruebas de Instagram, la mediana de líneas de código agregadas por las pruebas de TestGen-LLM fue de 2.5.

Insights accionables

  • Es un buen ejemplo de cómo usar LLM para mejorar de forma eficiente la productividad de desarrollo y la confiabilidad del software.
  • El verdadero valor de los LLM está en encontrar y capturar casos límite inesperados.
  • Para usar LLM en producción se necesita orquestación, pipelines y procesamiento.

Cómo funciona TestGen-LLM

  • TestGen-LLM aplica una serie de filtros semánticos a soluciones candidatas generadas por los LLM internos de Meta para conservar solo las pruebas más valiosas.
  • Filtro 1: capacidad de compilación, filtro 2: ejecución (si la prueba pasa), filtro 3: inestabilidad, filtro 4: mejora de cobertura.
  • Estos filtros de procesamiento garantizan la mejora de la suite de pruebas.

Conclusión

  • Este artículo es una buena forma de seguir los avances de los LLM en el espacio de confiabilidad del software, donde muchos desarrolladores ya los están usando.
  • Los LLM podrán encontrar errores y probar sistemas de software cada vez más complejos.

Opinión de GN⁺

  • Este artículo ofrece una visión interesante sobre cómo la inteligencia artificial puede influir en el futuro del desarrollo de software.
  • Herramientas como TestGen-LLM pueden ser de gran ayuda para automatizar el trabajo de los desarrolladores y aumentar la eficiencia.
  • El avance de estas tecnologías apunta a reducir la complejidad del desarrollo de software, mejorar la calidad y ahorrar tiempo a los desarrolladores.

1 comentarios

 
GN⁺ 2024-02-25
Opiniones en Hacker News
  • Es interesante la tendencia de querer usar LLM primero para escribir código de pruebas antes que para implementar
    Quizá sea porque hice demasiado TDD, pero veo las pruebas como una forma de describir cómo debe comportarse el sistema, y creo que esa parte la deben definir las personas. El código debe ajustarse a los guardrails creados por las pruebas
    Dicho eso, un LLM puede ayudar a señalar áreas donde faltan especificaciones. Tal vez lo que está pasando aquí sea pedirle que sugiera pruebas unitarias para partes menos especificadas
    Incluso antes de los LLM, a veces pensaba que, si uno escribía todas las pruebas, quizá un mono con una máquina de escribir podría construir la aplicación

    • En codebases legacy es común crear pruebas de caracterización (characterisation tests)
      Son pruebas que definen no cómo una persona cree que debería comportarse el código, sino cómo se comporta realmente el codebase actual
      Esto permite reescribir, refactorizar y rediseñar minimizando regresiones. El problema de mucho código legacy es que nadie entiende el comportamiento previsto y, a veces, hasta los usuarios creen que debería comportarse de una forma distinta a como realmente lo hace
      Por eso, si no se trata de un cambio deseado de forma explícita, lo más importante es no cambiar el comportamiento
    • Puede que ya lo conozcas, pero vale la pena pensar en pruebas basadas en propiedades (property-based testing). Hypothesis probablemente fue lo que más las popularizó y es recomendable, aunque no es el único enfoque ni la única implementación de alta calidad. También hubo una época en que QuickCheck de Haskell creció lo suficiente como para aparecer en HN
      La idea básica es expresar proposiciones sobre el comportamiento del código, más débiles que un sistema completo de pruebas en forma cerrada, como “propiedades”, y verificarlas dentro de límites esencialmente probabilísticos
      El ejemplo típico es invertir una cadena. Si inviertes una cadena dos veces, normalmente deberías obtener la entrada original. Con una sola línea de código puedes revisar tantos casos límite raros de Unicode como permitan el tiempo y la electricidad
      El ejemplo parece trivial, pero vi a expertos en CUDA que trabajaban en diferenciación automática y kernels, que luego se convirtió en PyTorch, usar este enfoque de forma increíblemente efectiva y obtener alrededor de 5 veces más confianza en el código con la mitad del esfuerzo y costo
      No siempre encaja bien, pero cuando encaja es excelente, y los LLM parecen poder acercarse bastante a ejemplos de Hypothesis en vez de empezar desde cero
    • Escribir código de implementación es mucho más divertido e interesante porque consiste en crear lo que la aplicación realmente debe hacer
      En cambio, al escribir pruebas tienes que describir lo que la aplicación debe hacer en un lenguaje extremadamente verboso y lleno de restricciones, y escribir decenas o cientos de líneas de configuración para meter unos cuantos if/else glorificados
      En lenguajes como C++ o Java, las pruebas unitarias están hechas de tedio, así que no sorprende en absoluto que surja el instinto de delegarle ese trabajo a un LLM
    • Puede ser porque muchos ingenieros, en la práctica, no hacen bien las pruebas
      He visto a muchos ingenieros programar durante días y luego, por obligación, escribir algunas pruebas para “demostrar” que el sistema funciona. La cobertura es baja y normalmente frágil
      Para un ingeniero que piensa y trabaja así, un sistema como este parecerá un regalo del cielo
      También tuve un gerente que prohibió escribir pruebas primero porque decía que era lento. Por suerte yo estaba como contratado externo, así que pude ignorarlo diciéndole “habla con mi jefe”, pero probablemente pensaba igual que los ingenieros de arriba
      Visto de otra manera, a la mayoría de los desarrolladores no les gusta la documentación. Les encantaría una IA que escriba excelente documentación a partir del código. Y para esos desarrolladores, una excelente documentación es la que no tienen que escribir ellos
    • Incluso fuera de la IA, al ver cómo se trata el código de pruebas, siento algo parecido
      El código de pruebas a menudo se trata como código de baja prioridad y se le asigna a ingenieros más junior, lo cual parece exactamente lo contrario de lo deseable
  • No quiero revisar todo el texto, pero una parte en particular parece estar bastante equivocada
    Parto de que leí el paper original por encima justo después de que salió y ahora lo estoy hojeando, así que mi memoria es borrosa
    El blog escribió que la mayoría de las pruebas de TestGen-LLM de Meta solo cubrían 2.5 líneas adicionales, pero que una prueba cubrió 1326 líneas, y que el valor de esa prueba era “exponencialmente mayor”, además de destacar el valor de que el LLM piense activamente fuera de la caja y capture casos límite inesperados
    Pero la expresión “exponencialmente más valioso” ya debería activar el detector de tonterías. Si miras el paper, los autores describen esa cobertura de 1326 líneas como una sola prueba que se sacó el jackpot, y dicen que la cobertura adicional realista esperada por una sola prueba de TestGen-LLM tiene una mediana de 2.5 líneas
    Los autores no mencionan “casos límite inesperados” ni “pensar fuera de la caja”. Más bien lo presentan como un caso excepcional que pudo haber tocado una rama de un switch espantoso o ser una casualidad de cómo se calcula la cobertura de código
    También llama la atención que en la sección de “resultados cualitativos” no profundicen más en esto. Las interpretaciones inexactas no ayudan a nadie. En internet ya hay demasiada gente que finge entender lo que fingió haber leído

    • Soy quien escribió el artículo, y no quise decir que los autores del paper hablaran de “casos límite inesperados” o de “pensar fuera de la caja”
      Modifiqué el texto para que quede más claro que algunas interpretaciones son mi opinión
      Este artículo es más un comentario sobre lo que implican los resultados del paper que un resumen del paper. Al fin y al cabo, Hacker News es un lugar para debatir
      Aun así, sigo creyendo que la parte de “exponencialmente más valioso” es correcta. Que un LLM pueda dar por casualidad con un “jackpot” en términos de cobertura de pruebas es precisamente el núcleo de su valor
      Si sigues probando muchas combinaciones y aciertas un solo jackpot como en el paper, eso ya puede ser muy valioso para el equipo. Puede tratarse de una prueba que no era obvia para escribir a mano o que era demasiado tediosa
      Desde mi experiencia en codebases de Big Tech (F/G), donde ya sabíamos qué había que probar pero pasábamos demasiado tiempo averiguando “cómo probarlo”, veo mucho valor en eso
    • Los incentivos de producción de código en Meta están mal en general
      Está claro que también están empujando a este equipo hacia métricas centradas en líneas de código y cantidad de diffs. Al final no será más que una herramienta de generación de código que crea otra montaña de código difícil de depurar
  • Las buenas pruebas son difíciles, y la cobertura no es necesariamente algo bueno
    Es fácil escribir demasiadas pruebas, terminar rigidizando el programa y, en la práctica, crear un programa de detección de cambios. Se vuelve algo como: “Cambiaste algo, todas las pruebas se rompieron. No pasa nada, ¡ahora le pedimos al LLM que las vuelva a generar! ¡100% de cobertura! ¡Increíble! ¡Progreso!”

    • De acuerdo. Las buenas pruebas son más de un orden de magnitud más difíciles que el buen código
    • Me parece interesante la perspectiva de “programa de detección de cambios”. Me pregunto por qué eso sería malo
      Para mí es una oportunidad de confirmar si ese cambio fue intencional. Sin eso, ¿cómo sabes si el programa hace lo que se supone que debe hacer?
    • Sin duda puedes saber que el código sin cobertura tiene pruebas pésimas
      Fuera de eso, tienes que leer las buenas pruebas que pensaron otras cinco personas. Todos escribimos mal las pruebas, cada quien a su manera
    • En un trabajo había pruebas de componentes web en las que se confirmaba un snapshot del DOM esperado y se verificaba que el componente emitiera eso
      Después, en cada cambio, el desarrollador naturalmente presionaba el botón de regenerar y confirmaba todo. El diff era abundante, pero la señal era dudosa
    • La clave está en los casos de cola larga
  • Después de haber trabajado en la industria de semiconductores, especialmente en litografía computacional, donde el diseño guiado por pruebas es el estándar, esto no me convence
    No significa que siempre tengas que escribir las pruebas antes que el código de producción. Pero las pruebas son tan parte del código como cualquier otra parte del codebase, y deben escribirse junto con el código que prueban
    La parte más importante de las pruebas es que muestran la intención del desarrollador. La suite de pruebas muestra cómo debe usarse el código, qué hace, qué no hace y para qué fue escrito
    Así, cuando otro desarrollador use o modifique ese código, no tiene que andar buscando pistas como Sherlock Holmes por todo el codebase
    Si las pruebas no cuentan una historia, las estás escribiendo mal
    Hasta que las computadoras puedan leer la mente y entender mejor la intención, un generador basado en AI/LLM no puede hacer este trabajo por nosotros
    Claro, si el único objetivo de la suite de pruebas es obtener una palomita verde en el chequeo previo al commit y mostrar números bonitos de cobertura, entonces puedes duplicar tu productividad con AI
    Los generadores automáticos de código te ayudarán a escribir más código malo a la velocidad de la luz. Si alguien se queja de que el código está inflado y es difícil de entender por tanto boilerplate, dile que lo resuelva con AI. A ti te funcionó
    Realmente parece que así será el futuro del desarrollo, pero no es el futuro que yo espero

    • Estoy de acuerdo con casi todo, pero creo que este tipo de pruebas también tiene su lugar
      Lo que describes parece más orientado a probar el “núcleo” del código. Son pruebas que también cumplen parte de la documentación, la verificación y la estabilidad
      Otras pruebas, como el fuzzing, ofrecen un valor completamente distinto. Creo que las pruebas basadas en AI pueden ocupar un espacio enfocado en la cola de la distribución: muchas pruebas de bajo valor que se dejan de lado por falta de energía y tiempo humanos
      Así veo también el estado actual de las herramientas de AI. Son herramientas de asistencia cognitiva
      Me sorprendería si esta línea de investigación no termina dando frutos bastante importantes en los próximos años
  • Cito de nuevo, con algunos retoques, lo que escribí cuando se publicó el artículo en sí. Su texto presenta mal las estadísticas
    https://news.ycombinator.com/item?id=39406726
    El resumen no coincide con el contenido real del paper. La síntesis hace que se lea como si fueran porcentajes por caso de prueba: “75% se compilaron correctamente, 57% pasaron de forma estable, 25% aumentaron la cobertura”
    El reporte real habla en términos de clases de prueba, y cada clase contiene uno o más casos de prueba
    Lo que significa es: “el 75% de las clases de prueba tenían al menos un caso de prueba nuevo que compilaba correctamente”, “el 57% de las clases de prueba tenían al menos un caso de prueba que compilaba correctamente y pasaba de forma estable”, “el 25% de las clases de prueba tenían al menos un caso de prueba que compilaba, pasaba y aumentaba la cobertura de líneas frente a otras clases de prueba del mismo target de build”
    Esas son dos afirmaciones completamente distintas. Incluso hay una nota al pie que dice que cada intento de extender una clase de prueba puede incluir varios intentos de generación de casos de prueba, por lo que la tasa de éxito por caso de prueba suele ser mucho más baja que la tasa por clase de prueba
    Pero en la conclusión vuelven a presentar mal los resultados, igual que en el resumen. Dicen que al usar TestGen-LLM en modo experimental, la tasa de éxito por caso de prueba fue del 25%, y que si se relaja el requisito de cobertura de líneas para exigir solo que compile y pase, la tasa sube al 57%

  • Siento empatía por quienes tendrán que mantener este pésimo código legacy de LLM en el futuro
    Va a ser horrible

    • Obviamente usarán un LLM para mantenerlo
    • Entonces los LLM no están eliminando empleos, sino creándolos. Aunque no parecen empleos muy divertidos
    • No creo que sea peor que el código estilo enterprise
      De hecho, quizá se vea bastante parecido, y puede que tenga comentarios y documentación más completos y menos probabilidad de estar activamente equivocado
    • Si borras las pruebas, problema resuelto. El dashboard de CI también mostrará la palomita verde
    • De acuerdo
      Los LLM nunca van a mejorar respecto de donde están ahora y no han avanzado nada en los últimos 2 años. No son más que cadenas de Markov vistosas
      Solo sirven para escribir código cuando alguien que no sabe programar lo confirma ciegamente en producción sin ninguna revisión
      Para alguien que sí sabe programar, no hay forma de que sean útiles ni de que aumenten la productividad
      Voy a ignorar esta tontería de los LLM que no cambiará el mundo en absoluto, y tú también deberías hacerlo
  • Si no se mantiene bien separado, fácilmente se convierte en un entorno hostil para los desarrolladores: un gerente ignorante exige una cobertura alta y juniors entusiastas meten a escondidas montones de pruebas con IA.
    Al final, cada vez que envías trabajo, tienes que conseguir el visto bueno de código de pruebas generado por LLM que es difícil de mantener.
    Es posible que escribir algunas pruebas sea más rápido, pero no hay garantía de que el mantenimiento sea más rápido. Lo mismo aplica al mantenimiento del código bajo prueba, porque no hay garantía de que se generen buenas pruebas.
    El proceso de sufrir al escribir pruebas normalmente también ayuda a que el desarrollador revise el diseño desde el principio. Si algo es difícil de probar, por lo general no es un buen diseño; por ejemplo, en un contexto donde hay que escribir código junto con otras personas, muchas veces el contrato del componente no está suficientemente abstraído.
    Un punto fácil de pasar por alto es que las pruebas son código sacrificable. La mayoría no atrapará nada en toda su vida, y eso está bien. Porque dan tranquilidad automatizada y, cuando hay una falla, reducen las pistas equivocadas.
    Pero invertir al máximo en una salvaguarda probabilística no siempre da recompensa. A medida que la cobertura se acerca al tope, la utilidad marginal disminuye. Si no se trata de rutas de ejecución con mucho tráfico, como en una biblioteca estándar, presumir de una cobertura alta por lo general no se ve recompensado.
    Además, casi siempre hace falta un ecosistema de pruebas —no solo pruebas unitarias, sino también pruebas de integración, pruebas de sistema, etc.— para que todo funcione. ¿Un LLM se sentará en las reuniones de diseño, entenderá la arquitectura y también escribirá esas pruebas? ¿O exagerará lo que puede hacer y desplazará lo que realmente hay que hacer?
    Al invertir esfuerzo en pruebas, se necesita criterio para decidir “qué es relevante”, no solo al escribirlas, sino también en el diseño y el mantenimiento. Los humanos somos bastante buenos en eso; las herramientas de IA no.
    Donde un LLM puede ahorrar tiempo es en las pulsaciones de teclado de un desarrollador experimentado que ya tiene una idea de qué conviene probar y qué no. Al mismo tiempo, también puede estorbar al colar en el código cosas poco relevantes, y de hecho ya lo ha hecho.
    No queremos una economía de producción de pulsaciones de teclado. Queremos un conjunto de pulsaciones de teclado bien pensadas y muy relevantes. Y esperamos que esto último se separe bien de lo primero, para que con el tiempo se haga evidente su utilidad objetiva, o la falta de ella.

  • Ya lo probé con GPT-4.
    Le mostré un módulo TypeScript y le pedí que generara pruebas unitarias; creó pruebas que funcionaban y cubrían no solo el camino normal, sino también varios casos límite.

    • No entiendo muy bien por qué comentarios similares reciben votos negativos.
      ChatGPT supera las expectativas en muchos aspectos. Las pruebas parecen fáciles para el nivel de capacidad de GPT.
      La semana pasada le hice escribir código Python que recorre un AST para crear un grafo y componentes de React Flow. No hice modificaciones; repetí varias veces la retroalimentación en el prompt y terminó funcionando muy bien. He visto muchas capacidades interesantes similares en GPT.
  • ¿Cómo sabe la IA qué pruebas debe escribir?
    Es un experimento interesante, pero me genera bastante desconfianza. Creo que la forma en que la IA puede ayudar mejor en el desarrollo de software es respondiendo cuando el programador hace preguntas sobre su propio código o el de otra persona. A veces incluirá sugerencias de código, pero no siempre tiene que ser así.
    Debería poder responder preguntas como “¿hay alguna forma de simplificar este código?” o “¿qué entradas podrían provocar errores?”.
    La IA debería ayudarnos a entender el código y a entender cómo mejorarlo. Si no le decimos qué queremos que haga, la IA no puede saber lo que queremos, así que no deberíamos dejar que escriba todo por su cuenta.
    Las pruebas son un buen ejemplo. ¿Qué queremos probar?

  • Por fin apareció una generación de código con IA que resulta convincente