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
Fico pensando bastante em que tipo de pipeline outros serviços de IA voltados para desenvolvimento estarão usando.
(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.
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
clineou noaidertambé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.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.
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.