31 pontos por xguru 2025-01-21 | 5 comentários | Compartilhar no WhatsApp

A combinação de TDD(Test-Driven Development) e LLM

  • TDD é uma metodologia de desenvolvimento em que se escrevem primeiro testes unitários abrangentes antes de começar a programar
  • Como os testes acabam funcionando, na prática, como uma especificação, quando todos passam no final é possível demonstrar até certo ponto a correção do código
  • Tradicionalmente, o TDD às vezes recebe críticas por prejudicar a produtividade ou ser ineficiente
  • Mas, com o surgimento dos LLMs, o processo de escrever testes e iterar corrigindo o código ficou muito mais fácil

Como costumo usar LLMs no dia a dia

  • Tenho usado ativamente ferramentas como o Github Copilot
  • LLMs são bons em encontrar padrões repetitivos e autocompletar as próximas linhas, mas muitas vezes têm dificuldade para entender profundamente o problema inteiro e produzir de uma vez um módulo completo e consistente
  • Quando se fornece contexto em excesso para resolver um problema, o modelo tende com facilidade a sair do foco
  • Se o trabalho avança fornecendo apenas partes das informações conforme necessário (como saídas de erro), o modelo também ajuda muito no debugging
  • Sinto na prática o atrito gerado por ficar repetindo copiar e colar entre IDE, terminal e interface de chat

Dá para automatizar?

  • Para automatizar esse processo, introduzi por conta própria o conceito de event loop
  • Ao especificar no primeiro prompt a especificação da função a ser implementada e a assinatura da função, o modelo propõe testes unitários e um rascunho do código
  • Esse código é salvo no diretório sandbox e o go test é executado automaticamente
  • Se os testes falham, o segundo prompt (iterativo) recebe junto o código existente e os resultados dos testes (erros de compilação ou informações sobre falhas)
  • Com base nisso, o modelo propõe novamente testes revisados e código de implementação
  • Esse processo se repete até que todos os testes passem
  • Essa abordagem permite melhorias graduais sem acumular contexto em excesso
  • O modelo pode falhar repetidamente no mesmo caso de teste; nesse caso, uma pessoa aponta diretamente a parte problemática e fornece uma dica
  • É preciso estar ciente do problema da “ausência de um fiscal”, ou seja, desconfiar se os testes criados pelo LLM são realmente rigorosos o suficiente
  • Há a possibilidade de código e testes compartilharem juntos o mesmo erro ou um design incompleto
  • Por isso, é importante que humanos reforcem adicionalmente os casos de teste
  • Se necessário, também dá para experimentar com IA técnicas como mutation testing

Desenvolvimento baseado em LLM e carga cognitiva (cognitive load)

  • Ao aplicar TDD com LLMs, espera-se que isso seja viável não apenas para problemas algorítmicos comuns, mas também em codebases reais com dependências de verdade
  • Ainda assim, é preciso dividir a estrutura do projeto em unidades menores para aumentar a manutenibilidade, e cada diretório/pacote deve poder ser testado de forma independente
  • Recomenda-se reduzir a carga cognitiva separando cada pacote entre as principais definições de tipos (shared.go), arquivos responsáveis por lógicas específicas (x.go) e testes (x_test.go)
  • No processo de usar IA, em vez de fornecer o código inteiro ao modelo toda vez, selecionam-se apenas partes específicas para ajudar o modelo a se concentrar
  • Isso aumenta a cobertura de testes e reduz o acoplamento entre módulos, o que também traz vantagens para a manutenção de longo prazo
  • Mesmo em projetos grandes, a ideia é buscar uma estrutura dividida em unidades pequenas e claras, que concentrem bem a lógica de cada unidade, mas mantenham o escopo mínimo

Encerrando

  • Considerando a velocidade do avanço da IA, é possível que já amanhã surja uma nova arquitetura capaz de superar as limitações dos LLMs
  • Por isso, em vez de refatorar abruptamente um grande código legado com mais de 100 mil linhas, recomenda-se explorar primeiro em pequena escala as possibilidades de combinar TDD e LLM
  • Espera-se que a fusão entre TDD e LLM traga mudanças positivas tanto para a geração automática de código quanto para a gestão da qualidade dos testes

5 comentários

 
jhj0517 2025-01-22

Fico pensando bastante em que tipo de pipeline outros serviços de IA voltados para desenvolvimento estarão usando.

 
halfenif 2025-01-21

(Vendo esse tipo de coisa) Daqui a pouco parece até que vão inserir eletrodos de estimulação elétrica no cérebro por causa de um cérebro cibernético.

 
crawler 2025-01-21

Acho que incluir código de teste é uma boa ideia, mas não me parece que haja alguma vantagem no programa que essa pessoa criou.
No cline ou no aider também dá para executar pela linha de comando e receber o resultado, então me parece melhor apenas usar bons prompts nesses programas, considerando as outras conveniências.

 
rabolution 2025-01-21

A abordagem do micro-agent feito pela Builder.io é parecida também. https://github.com/BuilderIO/micro-agent Eu também já tentei várias vezes usar LLM com TDD, mas é preciso fazer uma boa abstração, por exemplo com design systems. Também é preciso ter convenções e padrões bem estabelecidos. Os casos de teste eu normalmente escrevo à mão. (Nem que seja em linguagem humana?) Acima de tudo, como este texto também diz, é preciso projetar bem módulos com baixo acoplamento e alta coesão para conseguir encaixar o contexto dentro de uma janela de contexto limitada.

 
jamsya 2025-01-21

As LLMs lidam bem com código de escopo pequeno, mas ainda deixam a desejar em design geral e visão mais ampla,
parece uma boa abordagem combiná-los com TDD para ir melhorando aos poucos.