Por que só debugar não resolve o problema?

Photo by Pixabay from Pexels

O debugging (também conhecido pelo termo em português, depuração) é a ação de procurar e eliminar bugs no código, através do uso de diferentes ferramentas e técnicas. A maioria dos programadores tem uma relação de amor e ódio com o debugging: se por um lado ele é um processo necessário quando se está buscando por melhorias, em muitos casos ele acaba sendo demorado e estressante. Apesar da existência de IDEs e ferramentas que nos auxiliam nessa tarefa, debugar ainda é uma atividade que exige olhar minucioso. Um debugging mal feito e superficial pode levar a conclusões erradas e causar ainda mais problemas, visto que a correção de um bug pode causar muitos outros.

E é por causa desses perigos do debugging que certa vez eu ouvi alguém dizer que ele deveria ser evitado. Não o ato de debugar o código em si, mas o uso de ferramentas de debugging. Segundo essa pessoa, o único método realmente eficiente para debugar era ler o código, entender sua lógica e relações com demais blocos e módulos da aplicação, e então fazer o ajuste cirurgicamente. Bom, eu sinceramente não concordo com isso, primeiramente por que essa visão é meio utópica. O ser humano é falho e tem tendência a tirar conclusões erradas em muitas situações, seja utilizando ferramentas especializadas ou não. Ao andarmos por uma cidade que não conhecemos, podemos nos perder tanto de carro quanto a pé. Deixar de utilizar uma ferramenta não soluciona o problema, e podemos constatar que isso é verdade olhando um pouco para o passado.

Nos anos 60, a IBM começou a desenvolver um sistema operacional chamado OS/360. Em uma época na qual Windows e Linux não existiam, era normal que as fabricantes de computadores desenvolvessem seus próprios sistemas, o que era uma tarefa repleta de obstáculos. Não havia controle de versão, nem formas rápidas de comunicar a equipe sobre mudanças no projeto. Porém, debugar era o maior dos pesadelos, principalmente se analisarmos o quão mais complexo era fazer isso naquela época. No livro “The Mythical Man-Month”, um clássico da Engenharia de Software, Fred Brooks descreve seu dia-a-dia como gestor do time de desenvolvimento do OS/360 e explica o que um programador precisava fazer para debugar seu código, e é claro que tudo começa com uma boa dose de planejamento:

O programador cuidadosamente projetava seu procedimento de depuração, planejando onde parar, quais locais na memória examinar, o que procurar lá, e o que fazer caso não encontrasse (…). O pecado capital era pressionar START sem ter segmentado o programa em seções de teste com paradas planejadas.

OK, vamos parar pra pensar por um momento: quais passos precisamos seguir para debugar um aplicação hoje em dia? Bom, precisamos ler o código, analisar que linhas desejamos debugar e então marcar alguns pontos de parada (breakpoints). Com poucos segundos de análise e poucos cliques do mouse, conseguimos atingir esse objetivo. Na época não existia uma interface visual para realizar essa tarefa, o que significava que o programador precisava manipular a memória do computador através de comando em baixo nível. Achou esse planejamento todo muito complicado? Espere só até ver o que Brooks fala sobre a execução:

Em uma seção de 2 horas, um programador conseguia, talvez, uma dúzia de tentativas. (…) Então, quando impressoras de alta velocidade foram conectadas, a técnica mudou. Os programadores executavam o programa até que uma checagem falhasse, e então faziam o dump de toda a memória. Então começava o laborioso trabalho de mesa, checando o conteúdo de cada posição de memória.

Isso mesmo, você não entendeu errado: o debugging era feito no “olhômetro”, lendo centenas de posições de memória impressas no papel. Nada de passar o mouse na tela para verificar o valor das variáveis. E o pior de tudo; esse processo de executar-imprimir-analisar-repetir levava MUITO tempo. Se um programador conseguia executar seu programa aproximadamente 12 vezes em 2 horas, isso significa que cada execução levava em torno de 10 minutos. Além disso, como o autor enfatiza, computadores eram escassos, e provavelmente havia uma fila de programadores esperando para debugar em frente ao mainframe todo dia.

Como deu pra perceber, o debugging mudou muito nos últimos 50 anos. Mas se hoje em dia é tão mais fácil debugar, por que os bugs ainda são um problema? Por que empresas ao redor do mundo ainda gastam milhões por ano com retrabalho e correções, se agora estamos a apenas poucos cliques e breakpoints das respostas para nossas dúvidas? E é aí que entra o ponto central desse texto: de nada adianta mudar ou remover as ferramentas se o problema está em quem as usa, ou em que condições elas são usadas. Em minha opinião, a maioria dos bugs de software se resume a 2 coisas: o fator humano e o fator arquitetural.

Primeiramente, a velha constante: pessoas eventualmente cometem erros. A taxa de erro pode ser diminuída até um determinado ponto, mas todo sistema terá pelo menos uma porção de bugs causados por algum engano ou mal-julgamento do programador ou analista. Mas isso é completamente compreensível. O que realmente me preocupa é o fator arquitetural. Em muitas equipe de desenvolvimento há pouca preocupação em aplicar formalmente os conceitos de Engenharia de Software, preferindo-se fazer da forma que parece mais intuitiva e que dá uma falsa sensação de agilidade. Porém, metodologia ágil não é somente aquela que permite rápido desenvolvimento, mas que alia agilidade com código limpo, análise clara e que coloca as pessoas, sejam elas desenvolvedores ou usuários, em primeiro lugar.

Debugar é importante sim, e saber usar as ferramentas de debug é mais importante ainda. O que é um problema é quando esse tempo de debug se torna excessivo, e nesse momento a solução é colocar a mão na consciência e ver como a arquitetura da aplicação e o processo de desenvolvimento podem ser alterados. Utilizar técnicas de refatoração e reengenharia pode ser um bom começo, e criar documentação tanto para programadores quanto para usuários é imprescindível. No caso da criação de um novo sistema, fazer uma boa modelagem utilizando UML ou outras notações também é fundamental. E se você acha que planejamento é perda de tempo, prepare-se para muitas horas de debugging.

Fontes:

Nota: todas as citações foram traduzidas do inglês pelo autor deste post. A tradução é de inteira responsabilidade do mesmo.