Eustáquio Rangel

Desenvolvedor, pai, metalhead, ciclista

Qual a idade do seu repositório?

Publicado em Developer


Algum tempo atrás, durante uma reunião de sócios de um determinado projeto, um dos sócios o comparou com alguns outros projetos de outra empresa em comum, dizendo que uma das características do projeto era que, comparado com outros projetos, teoricamente era mais fácil de manter pois tinha uma base de código mais recente. Eu comentei que a base de código dele já tinha anos, mas fiquei curioso com uma coisa: quanto, das linhas de código desde o começo do projeto, ainda se mantém e quantas foram mudando durante a vida do projeto?

Achei interessante essa questão, pois já vi alguns projetos onde se apresenta aquele tipo de coisa que dá arrepios, "vamos reescrever tudo!", e a base de código muda mais do que fase da Lua. Quando ocorre esse tipo de reação, temos algumas explicações:

Temos algumas ferramentas que mostram frequência de código, como os gráficos do Github, com o de frequência de código mostrando quantas linhas foram inseridas e apagadas e o de commits, que mostra, durante um intervalo fixo determinado de tempo, a quantidade de commits feitas no repositório e também o GitStats, bem completo, que fornece várias estatísticas.

Mas eu queria alguma coisa bem no alvo da idade das linhas do repositório, até para tirar a dúvida do dito projeto. Para isso, eu fiz uma gem chamada Git::Age. A meta é verificar, no repositório, todos os arquivos que estão sob controle de versão e fazer um resumo, por mês e ano, de quantas linhas se encontram em determinada data e mostrar isso em um arquivo CSV e de forma gráfica. Para converter o arquivo CSV em uma imagem, utilizei o graph-cli, instalado via pip, com suporte para o Gnuplot em breve.

A utilização básica é a seguinte, entrando no diretório do seu repositório de código, após instalada a gem, executar:

$ git-age

Vamos ter um resultado parecido com isso, rodado em um projeto recente:

Waiting, analysing your repository ...
Reading files info from master branch ...
Creating CSV file git-age.csv with 11 lines ...                                                                                                                               
Creating image git-age.png ...
First commit in: 2022-02-09
Last  commit in: 2022-12-19
Repository has 314 days with commits
Month with more code lines unchanged: 2022-03 (26943 lines)

E vamos ter os seguintes arquivos criados localmente:

 $ ls git-age*
git-age.csv
git-age.png

Como não queremos poluir o repositório com arquivos desnessários e podemos querer alterar os nomes dos arquivos, podemos utilizar algumas opções para indicar isso:

$ git-age -o /tmp/project.csv -i /tmp/project.png

Agora temos os arquivos separados do repositório e com os nomes que especificamos, bem melhor! Dando uma olhada no arquivo CSV e na imagem gerada:

"date","code"
"2022-02",1825
"2022-03",26943
"2022-04",5717
"2022-05",3243
"2022-06",3882
"2022-07",1939
"2022-08",14589
"2022-09",1147
"2022-10",877
"2022-11",2589
"2022-12",2078

Imagem do projeto

No arquivo CSV e no gráfico, de forma visual, dá para ver que nesse projeto específico, que foi iniciado no começo do ano, a maior parte do código original dele foi inserida em 03/2022, com a segunda parte mais expressiva em 08/2022. Isso não mostra o que foi alterado e o que foi inserido de novo, mas dá a entender que a maior parte do código do projeto, que está rodando redondo, ainda é do começo do mesmo. Vale lembrar que nisso estão todas as coisas que envolvem mais volume, como os scaffolds utilizados na parte de parametrização do sistema, etc, mas já deixa claro que o projeto se desenvolveu em cima dessa base que ficou inalterada até agora. Se não precisou de alteração, talvez, eu disse talvez, essa é uma base sólida. Esses resultados ainda vão dar muita discussão filosófica.

Mas vamos dar uma olhada no projeto original da dúvida, que já começou a ser desenvolvido faz alguns anos, sendo que no final de 2019 que recebeu uma atenção maior e tração grande. Gerando o gráfico de forma similar, apresentou a seguinte imagem:

Imagem do projeto

Uau. Não falei? Aparentemente em algum momento ali houve muito código entrando. Pelo gráfico não dá para saber exatamente quando foi, pois as datas todas se misturaram, mas abrindo o CSV, dá para identificar mais de 40000 linhas de código feitas em 2019-12. Para tentar melhorar um pouco o gráfico em um projeto de longa duração, podemos utilizar a opção -p line (-t faz outra coisa, vamos ver logo abaixo) para gerar um gráfico de linha:

$ git-age -o /tmp/project.csv -i /tmp/project.png -p line

Imagem do projeto

Com base nesse gráfico, dá para afirmar sim, vendo o desenvolvimento tranquilo do projeto, que a maior parte do código que está nele já atualmente (agora é 2022-12) 3 anos e atualmente conseguimos trabalhar tranquilamente nele, criando mais recursos, em cima dessa grande base "legada", e das outras também (tem ao menos mais 3 picos menores anteriores). Se o projeto estivesse capengando agora, não seria necessariamente culpa dessa grande base de código, mas ali poderia ter algo que fosse uma fundação meio bagunçada da coisa. Enfim, temos código legado desde 2015, e a coisa continua tranquila.

Vamos deixar o gráfico um pouco mais bonito, especificando:

$ git-age -o /tmp/project.csv -i /tmp/project.png -p line -t 'Dados do projeto' -x 'Datas' -y 'Linhas'

Imagem do projeto

Com a dívida tirada - sim, temos uma base com bastante código legado funcionando corretamente - vem mais uma dúvida: eu sei como está a cobertura de testes do projeto, mas como esses testes foram se desenvolvendo durante o projeto? O correto, lógico, é sempre testes primeiro, mas será que durante o projeto foi feito isso? Tivemos mais linhas de teste antes, ao invés de junto com o código sendo desenvolvido? Fizemos mais testes depois? Para responder isso, de uma forma mais justa e mais bruta (não vamos eliminar linhas supérfluas para essa análise, como comentários) vamos especificar o diretório onde a maior parte do código e dos testes se encontram (são utilizados patterns de regex, então dá para brincar). Como é uma aplicação Rails, vou indicar o diretório app como do código e test (spec ou algo do tipo) como dos testes:

$ git-age -o /tmp/project.csv -i /tmp/project.png -p line -t 'Dados do projeto' -x 'Datas' -y 'Linhas' -e test -c app

Que gera 2 linhas, a azul com o código e a laranja com os testes:

Imagem do projeto

Fora umas escorregadas lá por 2020-06, até que o projeto está bem! E mesmo assim a dívida técnica dessa falta de testes foi paga no final de 2021. Interessante notar os picos de linhas de teste que aconteceram antes mesmo do maior pico de código em 2019-12 e também lembrar que aqui não são só as linhas de código de teste que foram produzidas, mas também persistidas, ou seja, a maior parte da suíte de testes do sistema foi acompanhando o seu desenvolvimento. Linhas de código que não são alteradas são indicativos interessantes que evitam bastante bugs de regressão, ou seja, aquele tipo de coisa que funcionava e de repente parou. Dá para notar que muita coisa ali da base do sistema está garantida que, mesmo que foi refatorada em algum momento, atende as necessidades dos testes feitos lá atrás. Um grande problema é alterar muito a suíte de testes, em algum refactoring ou manutenção, removendo alguns comportamentos que eram bem importantes de verificar.

Se precisarmos verificar como cada arquivo foi identificado, podemos utilizar a opção -m, que vai gerar um arquivo de mapeamento dos arquivos encontrados em /tmp/git-age.map, com todas as linhas, esse negócio vai ficar meio gigante dependendo do projeto, mostrando as categorizações deles:

$ git-age -o /tmp/project.csv -i /tmp/project.png -p line -t 'Dados do projeto' -x 'Datas' -y 'Linhas' -e test -c app -m

$ less /tmp/git-age.map
.gitignore[u]:
...
app/assets/javascripts/application.js[c]:
...
test/models/activity_type_test.rb[t]

Onde [u] é indefinido (nem código, nem teste), [c] é código e [t] é teste. Como mencionei anteriormente, esses dados são interessantes e cabe alguma discussão filosófica para o seu uso, mas não deixam de ser interessantes. Uma coisa interessante sobre o projeto daquele primeiro gráfico, usando as linhas de código e teste:

.

Imagem do projeto

Nesse projeto fizemos integração com o SAP Business One e no começo do projeto não conseguíamos simular o ambiente do SAP para executar nos testes, coisa que foi ficando mais tranquila conforme o projeto se desenvolvia. Já com conhecimento suficiente do ambiente, em 2022-08 pagamos a dívida técnica dos testes e agora no final do ano atingimos 100% de cobertura de código no projeto.

Apesar de ser uma gem feita em Ruby, o funcionamento é para qualquer tipo de repositório/linguagem. O que é levado em conta são as datas de cada linha de código nos arquivos controlados, os diretórios onde o código e os testes ficam são só localizações, não levando em conta em que linguagem estão escritos. Talvez mais para frente dê para implementar linhas ignoradas, etc. Enfim, foi um exercício que comecei fazendo de brincadeira e gerou essa gem.

A ironia é que a gem mesmo não tem testes! Fui desenvolvendo ela mexendo nos comandos do Git. Mas vai ter, assim como mais algumas coisinhas interessantes. :-)




Comentários

Sem nenhum comentário.

comments powered by Disqus

Artigos anteriores