Muitos desenvolvedores de software estão aprendendo ciência de dados para analisar os dados de seus clientes. O que cada vez mais gente percebe é que dá para usar essas mesmas técnicas para responder às suas próprias perguntas, como:
- Quando este projeto vai estar pronto para lançamento?
- Quais componentes do nosso aplicativo mais precisam de testes?
- Quem deve corrigir este bug?
- Quais partes da minha API as pessoas acham mais difíceis de usar?
Nos últimos 15 anos, houve uma explosão de pesquisas empíricas em engenharia de software para explorar essas questões, impulsionada em parte pela disponibilidade de dados de sites como GitHub e Stack Overflow. Este post apresenta alguns resultados representativos e, em seguida, aprofunda os métodos por trás de três deles.
Se você quiser saber mais sobre como usar ciência de dados para obter insights como esses nos seus próprios projetos, fale comigo.
Ciência de dados e engenharia de software: exemplos
Comecemos com uma descoberta que afeta todo mundo que faz ciência de dados em escala: a descoberta de Yuan et al. de que testes simples podem evitar a maioria das falhas críticas em sistemas distribuídos intensivos em dados. Eles analisaram falhas no Cassandra, Hadoop MapReduce e sistemas semelhantes e constataram que:
- Quase todas as falhas exigiam 3 ou menos nós de computação para serem reproduzidas. Ou seja, geralmente você não precisa de um cluster para depurar um cluster.
- Os logs de erro normalmente continham dados suficientes para permitir a reprodução.
- A maioria das falhas catastróficas poderia ter sido evitada com facilidade realizando testes simples no código de tratamento de erros.
O último ponto é o mais inesperado. Embora profissionais geralmente testem se seu código de análise funciona quando tudo está bem, raramente testam se ele faz a coisa certa quando algo dá errado. Incluir alguns desses testes durante o desenvolvimento evitaria muita dor de cabeça lá na frente.
Outro resultado em larga escala vem do trabalho de Altadmri e Brown, que analisaram 37 milhões de tentativas de compilar programas feitas por alunos do ensino médio no Reino Unido. Eles então perguntaram aos professores quais eram os erros mais comuns dos alunos e descobriram que:
- Os professores não concordavam entre si sobre quais erros os alunos eram mais propensos a cometer.
- Mais importante: as previsões dos professores tinham pouca correlação com o que os alunos realmente erravam.
Claro que mineração de dados não é a única forma de gerar insights úteis baseados em evidências em programação. Em 2013, a equipe de Andreas Stefik publicou o segundo de uma série de estudos sobre se algumas linguagens são mais fáceis de aprender do que outras. Como linha de base, eles incluíram no estudo uma linguagem inventada cujas palavras-chave foram geradas aleatoriamente.
Para surpresa deles, linguagens com chaves como Java e Perl foram tão difíceis para iniciantes aprenderem a reconhecer quanto uma linguagem gerada aleatoriamente. Python e Ruby foram significativamente mais fáceis de aprender, e Quorum, que faz testes A/B da sintaxe de cada novo recurso antes de adicioná-lo, foi ainda mais fácil. Andreas comenta esse resultado e por que projetistas de linguagens de programação dão tão pouca atenção à usabilidade neste podcast divertido.
Identificando relatórios de bugs de segurança
Como exemplo de como esses estudos são feitos, Fayola Peters, do LERO, usou modelos de predição baseados em texto para encontrar relatos de bugs de segurança nos rastreadores de bugs de grandes sistemas, a fim de priorizar o trabalho neles. Em um estudo, ela usou dados dos projetos Chromium, Wicket, Ambari, Camel e Derby; esses reúnem um total de 45.940 relatórios de bugs, mas apenas 0,8% são sobre segurança.
Alguns bugs de segurança são rotulados manualmente, e esses podem ser usados para treinar classificadores que detectam itens sem rótulo. Técnicas como Naïve Bayes e Random Forests são um ponto de partida, mas a eficiência de modelos genéricos pode ser melhorada filtrando palavras-chave específicas. A verificação mais importante é o quão bem modelos treinados em projetos com bugs de segurança rotulados conseguem encontrar bugs semelhantes em outros projetos. Os resultados foram animadores: Peters constatou que seus classificadores eram bons o suficiente para uso prático.
Meu patch vai ser aceito?
Como segundo exemplo, empresas querem ver suas modificações incorporadas aos projetos para evitar manter o código por conta própria, e voluntários também querem ter uma indicação de suas chances. Como muitas vezes há um longo intervalo entre o envio e a aceitação de um patch, Bram Adams e seu grupo na Polytechnique Montréal vêm construindo modelos para prever quais serão aceitos.
Como em muitos projetos de ciência de dados, tudo começa obtendo e limpando dados de várias fontes, incluindo repositórios Git e revisões de código no Gerrit. Porém, para projetos que usam revisão por email, como o kernel do Linux, coletar dados significa fazer scraping de arquivos de listas de discussão e usar heurísticas, como checksums de patches ou interseção baseada em conjuntos de linhas alteradas, para casar patches com conversas. Mesmo com a ajuda de ferramentas como o GrimoireLab, sempre haverá patches com várias versões revisadas e patches divididos em várias partes revisadas separadamente. Como em toda ciência de dados, cabe ao analista construir um modelo, e as suposições nele terão grande impacto nas conclusões finais.
O segundo passo é decidir quais variáveis examinar e qual métrica usar para cada uma, como:
- qualidade do patch
- experiência de quem desenvolveu o patch
- processo de revisão (por exemplo, comentários de revisão e número de revisores)
- qualidade da revisão (por exemplo, nível de detalhamento das revisões)
- tempo de revisão
- interação entre autor do patch e revisores (por exemplo, tom amistoso versus agressivo)
Só esse conjunto já pode exigir de tudo, de análise de sobrevivência a análise de sentimento. Depois de decidir o que medir, você pode aplicar as ferramentas de ciência de dados que os cursos da DataCamp ensinam. Como seu objetivo real é prever a aceitação de patches futuros, a abordagem mais direta é a regressão logística, mas há várias outras opções.
Por fim, você pode medir a importância das variáveis para determinar o impacto de cada uma na aceitação do patch. Isso será necessariamente em parte qualitativo, já que a meta é identificar o que os desenvolvedores podem fazer para aumentar as chances de seu trabalho entrar no produto. Como sempre, é preciso cuidado para não confundir correlação com causalidade, mas até algumas recomendações simples (como "NÃO USE CAPS LOCK NAS MENSAGENS DE COMMIT") já fazem diferença.
Encontrando ajuda
A maior mudança em como programadores trabalham nos últimos 20 anos não foi nas linguagens que eles usam: foi a dependência quase universal do Stack Overflow para perguntar e responder dúvidas. Christoph Treude, da Universidade de Adelaide, e seus colaboradores vêm desenvolvendo métodos para tornar sites como esse ainda mais úteis.
O ponto de partida é o dump de dados do Stack Overflow. Depois de fazer estatísticas exploratórias para observar número de palavras e frases, palavras mais comuns, TF-IDF (term frequency–inverse document frequency) e assim por diante, o próximo passo é ver quais palavras nas threads do Stack Overflow coocorrem com mais votos, maior taxa de aceitação e mais visualizações.
Como a documentação de software contém muitas frases incompletas e elementos de código, bibliotecas de NLP prontas costumam errar. Documentação de software escrita em outras línguas além do inglês é ainda mais difícil de analisar, já que tende a usar inglês para a terminologia técnica. Ou seja, mistura duas línguas naturais e elementos de código. É preciso combinar heurísticas ad hoc com técnicas de modelagem mais avançadas para lidar com esses casos.
Juntando as peças, é possível construir uma ferramenta que recebe o nome de um módulo Python como entrada e produz frases significativas sobre esse módulo a partir das threads do Stack Overflow. Indo além, Treude e seus colaboradores conseguiram usar dependências gramaticais entre palavras para encontrar automaticamente documentação de software que explica como realizar uma tarefa e, depois, identificar automaticamente trechos de código que a executam.
Conclusão
Muitas vezes, “verdades” difundidas sobre desenvolvimento de software se baseiam mais em opiniões fortes e vozes altas do que em evidências. Como descrito no começo, isso está mudando à medida que centenas de estudos de alta qualidade surgem todos os anos para sustentar algumas crenças, como “code review é realmente a melhor forma de encontrar bugs”, e questionar outras, como “test-driven development não é tão eficaz quanto alguns acreditam, e instruções goto não são necessariamente prejudiciais”.
“Engenharia” já foi definida como “a aplicação do método científico para criar coisas úteis”. Se isso é verdade, então o desenvolvimento de software, graças à ciência de dados, pode finalmente estar a caminho de se tornar uma disciplina de engenharia de fato. Se você quer ver cursos que mostram como aplicar ciência de dados ao desenvolvimento de software, conte para a gente.
Para saber mais
Pesquisadores apresentam dezenas de novos achados nessa área todos os anos em conferências como a Mining Software Repositories. Parte desses anais ainda está atrás de paywalls acadêmicos, mas cada vez mais pesquisadores disponibilizam preprints.
Para quem busca uma visão geral, o livro de 2010 Making Software foi uma coletânea dos “melhores momentos” dos resultados mais interessantes da época. Uma nova trilogia intitulada Perspectives on Data Science for Software Engineering, The Art and Science of Analyzing Software Data e Sharing Data and Models in Software Engineering oferece uma cobertura mais ampla e atualizada dos mesmos temas e, em paralelo, Derek Jones está trabalhando em um novo livro intitulado Empirical Software Engineering Using R.


