Como a ciência pode te ajudar a resolver bugs

Como a ciência pode te ajudar a resolver bugs


Está na moda falar sobre ciência. Em meio a uma pandemia algumas pessoas estão louvando-a (estou nesse grupo talkey!) e outras odiando. Mas creio que muitos nem conhecem como a ciência funciona. Entender como ela funciona pode te ajudar em muitas coisas na sua vida, muitas decisões práticas podem ser tomadas de forma melhor se conhecermos o método da ciência. Método??!?! Sim meu caro, ciência é um método e não um ser mágico que detêm o conhecimento do além de como as coisas funcionam.

Mas antes de começarmos vou fazer uma pergunta: Qual é o seu método? Talvez você não saiba responder a essa pergunta, mas você tem sim um método. Esse método pode ser até descrito. Tenta refletir aí baseado nas perguntas abaixo:

  • O que você faz quando recebe um ticket para implementar?
  • O que você faz pensa quando sabe que tem um bug?
  • Como você aprende?

Tudo tem um método, as vezes ele é completamente subconsciente e emocional. Mas você pode refletir sobre ele e mudar ele.

Como funciona o Método Científico?

Aviso: Eu não sou filosofo e nem cientista e minha faculdade não tinha nenhuma matéria sobre método científico, logo não leve minhas afirmações como últimas, elas podem estar imprecisas. Aprendi sobre método científico na prática em laboratório de física.

A base do método científico é a formulação e validação de hipóteses. Mas como isso funciona? Vamos dividir em passos e explicar cada passo pensando na solução de bugs.

  1. Observação
  2. Formulação de hipóteses
  3. Elaboração de experimentos
  4. Validação das hipóteses
  5. Análise de dados
  6. Conclusão

1. Observação

A primeira coisa que devemos fazer quando nos deparamos com um bug é observar o que está acontecendo. Nesse caso precisamos levantar dados como em que ambiente o bug acontece, qual o contexto, saber se o sistema está sob estresse, há outros processos rodando na mesma máquina, quais foram as alterações recentes e quem fez, etc… Quanto mais perguntas você fizer nessa fase, mais informações vai ter.

É muito importante saber todo o contexto, porque em muitos casos bugs são criados por efeitos colaterais de outras alterações e algumas soluções podem desfazer alterações prévias que são requisitos necessários.

No final, a observação deve resultar em coleta de logs do sistema. Se o erro acontece sem nenhuma mensagem de erro ou alerta, isso por si já faz parte do bug.

2. Formulação de hipóteses

O segundo passo é formular hipóteses. Desenvolvimento de software também é baseado em hipóteses, algumas delas são requisitos e outras são padrões arquiteturais.

A hipótese é nada mais do que uma afirmação sobre o contexto. Por que é importante formular hipóteses? Porque não podemos simplesmente sair alterando código sem saber o que ele faz. Precisamos ser cirúrgicos nas nossas alterações para evitar efeitos colaterais. Se formos cirúrgicos em nossas alterações, o código vai ficar cada vez mais estável, caso contrário teremos cada vez mais bugs em um processo que custará cada vez mais caro para o desenvolvimento. Nada é pior do que código instável.

Quer exemplos de hipóteses?

  • O arquivo de configuração não está sendo lido
  • O processo não tem permissão de leitura
  • O HD está cheio
  • Há um memory leaky e o processo está sendo finalizado pelo sistema operacional

3. Elaboração de experimentos

Agora que temos uma hipótese, precisamos validar ela, mas para isso temos que fazer experimentos. Como eu posso criar um experimento a partir de uma hipótese? Nosso camarada Karl Popper pode nos ajudar (acho que era outro Karl? 🙃), precisamos falsear essa hipótese.

Falsear é um termo que pode parecer estranho, mas é como se pegássemos nossa hipótese e tentássemos ver como ela pode ser refutada. Esse é o princípio básico para se criar testes. Se eu tenho uma hipotese que o erro acontece por um motivo, será que eu consigo criar um teste que reproduz aquele erro?

Vamos tentar fazer isso com nossa primeira hipótese? Se o arquivo de configuração não está sendo lido, quais são as possibilidades que podem fazer isso acontecer? Será que ele existe? Se ele não existir há uma mensagem de erro? Será que o caminho dele está certo? Será que há alguma variável de ambiente que sobrescreve ele? Será que há algum erro no arquivo, algum parâmetro escrito de forma incorreta? Quais mensagens de logs demonstram isso?

Falsear é refletir sobre a hipótese e em como construir testes que validem a hipótese. É simplesmente tentar destruir ela a todo custo.

4. Validação das hipóteses

Agora com minhas suposições, precisamos criar testes para validar se é realmente isso que está acontecendo. Esses testes podem não ser testes automatizados, pode ser apenas “pede pra pessoa de operação executar df -h e me mandar a resposta”.

Ou pode ser criar testes mesmo, no nosso exemplo, o que acontece se existe um arquivo de configuração especificado, mas ele não existe? Deve aparecer algum erro? O processo deve ser finalizado? Criar os testes automatizados podem ser importantes para que alterações futuras não tragam o erro de volta.

Nessa fase da validação de hipóteses é necessário em muitos casos voltar a fase de observação. Na grande maioria dos bugs de produção não há dados para prever ele porque ninguém imaginava que ele poderia acontecer.

5. Análise de dados

Ao executar os testes, temos mais dados. Mas será que os testes realmente reproduzem o problema? É nessa hora vamos comprovar nossa hipótese. Se a mensagem de erro é a mesma ou o comportamento é similar podemos assumir que nossa hipótese é válida, caso contrário precisamos de uma nova hipótese e assim voltamos ao passo 2. É muito importante que o erro seja reproduzido, pois só assim sabemos quais condições o levaram a acontecer.

6. Conclusão

Ora, na ciência temos uma hipótese validada, mas e em desenvolvimento de software? Também temos uma hipótese validada! E isso pode levar a várias ações. Observe que nesse processo eu não falo de ações ou correções, pois esse é o processo de encontrar o problema.

Mas dada a nossa hipótese, quais ações devem ser tomadas? O processo deve ser executado com permissão de administrador? O processo deve ser finalizado se houver um erro no arquivo de configuração? O software deve sempre colocar no log as configurações lidas? O software deve validar se tem permissão de leitura/escrita de certos arquivos?

É muito importante que a conclusão leve a possíveis requisitos de automatização. Isso pode ser feito com a criação de testes ou com dashboards para validar a operação. O conceito de observabilidade é muito importante, devemos ter dados sobre a operação que possam validar e guiar o desenvolvimento.

Conclusão

Método é importante, sem ele atuamos cegamente sem sabermos o que realmente estamos fazendo. Há vários métodos no desenvolvimento de software e as vezes não pensamos sobre eles, como desenvolvimento tempos o Test Driven Development que é um método bem comum. Ter método é bastante útil porque nos ajuda a não procrastinar, sabemos como iniciar a fazer e quais são os passos. Em muitos casos a procrastinação é o medo de executar por não saber.

Agora que você conhece como eu aplico o Método Científico no meu trabalho do dia a dia, me manda um oi para ver se eu te ajudei!

Se quiser conhecer mais sobre Karl Popper, eu achei esse texto simples no blog Nau dos Loucos: Falseabilidade Descomplicada: Karl Popper e o Falsificacionismo

Licença Creative Commons
Este obra está licenciado com uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 4.0 Internacional .