Do jupyter notebook para código profissional – Parte 1


1 – Introdução

Neste texto irei discorrer sobre inúmeras sugestões que transformarão seu código em algo mais profissional, mais fácil de se consertar, expandir e reusar para você e para outras pessoas que venham trabalhar na sua equipe. Será necessário mais do que essas poucas linhas aqui escritas para atingir este objetivo portanto a intenção deste post é informar sobre o que é necessário saber e o por quê para que os leitores possam buscar por conta própria cada um desses quesitos que por si só já dariam para se escrever inúmeras páginas.

Na jornada do cientista certamente ele encontrará inúmeros exemplos, posts e aulas falando sobre como implementar esse ou aquele modelo a um dado assim ou assado na vasta maioria das vezes usando o Jupyter Notebook ou Google Colab.

Porém para desenvolver um produto é necessário muito mais do que só o código como nos foi ensinado e saber o que precisa ser feito pode fazer uma diferença enorme no projeto no longo prazo.

Quem já entrou em um projeto em andamento ou retomou um projeto próprio do passado, muitas vezes sente dificuldade de entender e contribuir dependendo do que foi (e do que não foi) feito. Isso faz parte da chamada “tech debt” (“dívida tecnológica”), problemas do projeto inicial que foram se acumulando em prol de uma entrega rápida mas que geram problemas mais a frente.

Após ler este post e a parte 2 espero que o leitor possa pelo menos estar ciente da dívida técnológica e como dar conta dela.

2 – Classes

Os algoritmos criados em geral receberão dados, prepararão eles e gerarão resultados, desta forma todas as informações específicas sobre as estatísticas dos dados usados durante o desenvolvimento, os gráficos e resultados possivelmente não serão mais necessários. Somente usaremos o código que recebe, processa e gera novos resultados.

Portanto, a primeira coisa a ser feita é usar classes para o código inteiro. Desta forma podemos naturalmente eliminar as linhas desnecessárias e tornar o código mais legível e reutilizável além de considerar o princípio de não se repetir (DRY – don’t repeat yourself) e a possibilidade de usar heranças (inheritances).

A reorganização do código em classes em geral é feita dividindo o código em partes, cada uma em um arquivo .py diferente e uma classe diferente, por exemplo, uma classe para limpar os dados, outra para gerar estatísticas básicas (se necessário), outra classe para o modelo e outra classe para o pós-processamento.

3 – Documentação

É impressionante, mas a documentação é possivelmente a coisa mais importante e mais ignorada em projetos internos. Apesar de termos inúmeros exemplos de como escrever documentação em projetos públicos, muita gente simplesmente ignora esse ponto super importante de um projeto.

Desenvolvedores ignoram por estarem concentrados no código e não acharem que é algo que vale investir tempo e muitos clientes ignoram a necessidade por achar que é algo que gera custo sem trazer benefícios.

Por mais que seja importante construir MVPs de forma rápida e barata quando se quiser expandir, dar suporte ou entender como a ferramenta funciona, só aí que será sentida a falta da tal documentação.

Mas mesmo quem está convencido da sua importância pode estar se perguntando o que exatamente seria necessário para uma boa documentação?

3.1 – Explicação geral

Uma maneira simples de se começar a documentar um projeto é escrever uma explicação geral sobre o objetivo, método, dados e referências. Como muitos projetos necessitam de uma proposta técnica para serem aprovados esses documentos podem servir de base ou o próprio documento original pode ser usado para servir a esse propósito.

Aqui tem um exemplo de um documento que eu fiz sobre um algoritmo usando reinforcement learning para investimentos e aqui tem outro exemplo de um projeto no qual trabalhamos para melhorar um algoritmo já existente e por isso tem uma seção chamada “Issues of v1 implementation”.

Em ambos os documentos percebemos que todos os detalhes técnicos não foram dados pois o objetivo era só mostrar algumas ideias principais do projeto e até porque em ambos os casos os leitores não eram da área técnica e provavelmente não entenderam os poucos detalhes listados mas pelo menos entenderam a ideia geral do que foi utilizado e por que. Apesar disso, leitores mais técnicos vão ter uma ideia do que foi feito mas sem serem sobrecarregados inicialmente com uma montanha de detalhes.

3.2 – Dicionário de variáveis

Outro exemplo bizarro sobre falta de documentação é a falta de dicionários das variáveis. Este documento lista todos os campos das tabelas geralmente com uma pequena descrição da variável, o tipo da variável (exemplo: categoriais, número, texto, etc) e os valores que ela pode assumir caso seja relevante. Em alguns casos ele também contém informações sobre 

Primary keys e foreign keys, observações sobre regras de negócio, origem da informação, entre outras informações que possam ser consideradas importantes no projeto.

Por exemplo, se o nome de uma variável é “sexo” será que ela é simplesmente uma letra como “h”, “m”, “o” para “homem”, “mulher” ou “outro”, será que ela são uma palavra inteira (e quais palavras?) ou será que elas estão codificadas como números como 0, 1 e 2? 

Nos meus quase 20 anos de experiência eu só vi dicionário de variáveis em dados públicos (aqui tem um exemplo para o censo escolar) e em algumas API e bibliotecas públicas. Mesmo em projetos grandes esse é um documento muitas vezes negligenciado e que eu tive o desprazer de ter que fazer do zero. 

O curioso é que dada a pressão por “produtividade” dos agentes de negócios muitas equipes não produzem esse documento na expectativa que se necessário irão de recordar dos detalhes dessas informações mas na hora de por no papel essas informações eles acabam descrobrindo que não sabem dar informações sobre esses dados e para descobrir pode levar muito tempo.

Bons dicionários podem reduzir a quantidade de erros, reduzir o tempo de desenvolvimento de ferramentas, evitar conclusões erradas ou mal interpretadas e portanto têm um efeito negligenciado muito mais importante do que muita gente pensa.

3.3 – Docstrings

De todas as partes da documentação comentadas essa provavelmente é a mais importante. A cada método de cada classe e a cada função é super importante escrever docstrings descrevendo para que serve, quais são as variáveis de input e variáveis de output. 

Caso suficientemente bem feita o dicionário se torna desnecessário pois suas informações podem estar nas docstrings porém na maioria dos casos mesmo que existam docstrings, elas geramente não contem informações suficientes sobre os dados o que é algo muito ruim.

3.3.1 Comentários ou Docstrings?

Existe uma certa discussão sobre a necessidade de escrever comentários explicando cada linha de código porém eu já vi desenvolvedores dizendo que se o código é limpo a linha é óbvia e portanto não é necessário escrever comentários, só a docstring é suficiente. Eu prefiro uma posição mais no meio do caminho, escrever comentários ou para explicar o objetivo de um certo bloco de código e comentários para linhas que possam ser um pouco complicadas e que não seja muito claro o que ela faz.

Na prática a questão da necessidade de comentários me aprece muito relacionada a experiência do desenvolvedor, os mais experientes escrevem código limpo, padronizado e claro e portanto acham desnecessário escrever comentários mas muitas vezes acabam não dando a devida importância as docstrings também. 

Já desenvolvedores iniciantes tem certa dificuldade de escrever código de alta qualidade e portanto podem achar necessário escrever muitos comentários. Se o desenvolvedor não sabe escrever código claro é melhor escrever comentários mesmo, pelo menos outros desenvolvedores poderão acompanhar o que foi feito porém é importante evitar comentários quando a linha faz algo muito óbvio ou padrão.

Algo parecido acontece com quem precisa ler o código, desenvolvedores experientes tem mais facilidade para ler e entender código e portanto podem achar que o excesso de comentários atrapalha a legibilidade do código, enquanto desenvolvedores iniciantes vão ter dificuldade de acompanhar código, principalmente se for código ruim, mesmo que cheio de comentários.

Certamente é uma situação difícil de se lidar, a única solução é bom senso, paciência e compreensão.

Conclusão

Espero que os leitores estejam gostando deste post, quando eu inicialmente pensei em escrevê-lo eu nem imaginava que teria tanta coisa para dizer sobre o assunto mesmo que tão superficialmente. 

Convido-os a lerem o parte 2 quando estiver disponível aonde pretendo falar sobre os tipos das variáveis, logs, padrões e performance.

Para quem quiser aprender comigo como implementar essas sugestões além de aprender alguns modelos de otimização de inteiros sugiro se inscreverem no meu curso em parceria com a Comunidade de Estatística do Prof. Thiago Marques.