Esquecendo o PDD e aprendendo a debugar

Já faz algum tempo em que eu via as pessoas programaram em C++ com a utilização do Visual Studio, famosa IDE da Microsoft. Nesta época eu tinha a tarefa de transcrever algumas metodologias estatística em pseudo-código para que as mesmas fossem implementadas por algum desenvolvedor em C++. Até aí nada demais, mas volta e meia o código quebrava e lá começava-se o ciclo vicioso na procura de onde estava o erro - e um detalhe importante: o código era complexo, grande parte das ferramentas tinham sido implementadas - e pensando assim, achar onde estava o erro seria um verdadeiro pesadelo.

Porém o Visual Studio contava com uma ferramenta bem conhecida já por desenvolvedores, e pouco aproveitada pelos usuários um pouco menos hardcores, que é o modo debug. Lá funcionava da seguinte forma: O desenvolvedor escolhia alguns pontos onde ele desejava explorar o valor de variáveis locais e mandava o programa executar, então com isso ele seria possível executar linha a linha em tempo real explorando cada uma daquelas variáveis que estavam sendo criada ou alteradas. E isto era simplesmente fantástico !

Geralmente a tática utilizada pelos usuários menos experientes é o famoso PDD(Print Driven Development) que significa mais ou menos o seguinte: Se deu algum erro, imprime um monte de coisa. É provável que neste processo você se perca no meio de tanta informação impressa. E neste post vamos ensinar uma alternativa ao PDD. Antes de tudo, nada contra o PDD. Eu mesmo fui um forte usuário desta famosa técnica por muito tempo, antes de descobrir como debugar códigos, porém temos que confirmar que o trabalho de inserir vários prints e depois removê-los é bem árduo. Então só o trabalho economizado ao não inserir/apagar estes prints já vale a pena, na minha opinião. Para quem utiliza o Revolution R ou o RStudio, estes já possuem um modo de debug incluso na IDE, então é mais fácil ainda.

Mas afinal, o que significa debugar um código? Podemos dizer de forma grosseira que debugar um código é executá-lo e explorá-lo em tempo real. Então vamos a um exemplo simples.
Uma função que recebe um inteiro e um múltiplo, então retorna todos os números até aquele inteiro multiplicado pelo múltiplo.


calcula_multiplos = function(tamanho, multiplo)
{
    vetor_multiplo = c()
    for(iesimo in seq(tamanho))
    {
        iesimo_multiplo = iesimo * multiplo
        vetor_multiplo = c(vetor_multiplo, iesimo_multiplo)
    } 
    vetor_multiplo
}

É uma função simples, que aproveitando as propriedades vetoriais do R, sequer precisaria de um for para isso. Mas a intenção é aqui é mostrar como funciona o debug mode. Para acessar a ferramenta, precisamos em primeiro caso, ativar a função como debug mode.

 debug(calcula_multiplos)

Feito isso, sempre que a função for executada, o modo debug será ativado. Com isso, o modo browser será aberto e a função será executada linha a linha. Em cada passo, os seguintes comandos podem ser dados:

  • n : Avança para a próxima linha.
  • c : Avança para o próximo bloco. Em termos práticos significa avançar o loop ou seguir para a próxima função, caso tenha funções aninhadas.
  • cont : Mesma coisa que o c.
  • where : Indica em que ponto do código você está.
  • Q : sai do modo browser e volta ao prompt de comando do R.

Um detalhe interessante é que se você executar a função ls() de dentro do prompt, serão exibidos apenas os objetos que pertencem aquele ambiente, diferentemente do ls() normal, onde é exibido o ambiente global do R. Então para a nossa função anterior, aqui vai um exemplo de como seria o debug mode.

 calcula_multiplos(3, 7)
calcula_multiplos(3, 7)
debugging in: calcula_multiplos(3, 7)
debug at #2: {
    vetor_multiplo = c()
    for (iesimo in seq(tamanho)) {
        iesimo_multiplo = iesimo * multiplo
        vetor_multiplo = c(vetor_multiplo, iesimo_multiplo)
    }
    vetor_multiplo
}
Browse[2]> n
debug at #3: vetor_multiplo = c()
Browse[2]> n
debug at #4: for (iesimo in seq(tamanho)) {
    iesimo_multiplo = iesimo * multiplo
    vetor_multiplo = c(vetor_multiplo, iesimo_multiplo)
}
Browse[2]> n
debug at #4: iesimo
Browse[2]> n
debug at #6: iesimo_multiplo = iesimo * multiplo
Browse[2]> n
debug at #7: vetor_multiplo = c(vetor_multiplo, iesimo_multiplo)
Browse[2]> iesimo_multiplo
[1] 7
Browse[2]> where
where 1: calcula_multiplos(3, 7)

Browse[2]> 
debug at #4: iesimo
Browse[2]> c
debug at #9: vetor_multiplo
Browse[2]> n
exiting from: calcula_multiplos(3, 7)
[1]  7 14 21


Como podem ver, pouca coisa foi executada e explorada. Na verdade apenas em 2 momentos foi realmente utilizado, quando vi quem era o primeiro iesimo_multiplo e quando vi em que ponto da execução estava com o where. Logo depois sai do for e a chamada da função terminou. Feito isso, temos que sair do debug mode, caso contrário sempre que chamarmos a função, o debug mode será executado, e não queremos isso. Se utilizarmos a função debugonce(calcula_multiplos), a mesma será debugada apenas uma vez. Caso contrário temos que utilizar a função undebug(calcula_multiplos).

 undebug(calcula_multiplos)

Com isso, sabemos tudo que precisamos para utilizar o debug mode e não mais o PDD, ainda que este seja realmente útil e provavelmente mais simples e intuitivo, porém quando se trata de funções maiores e aninhadas, pode ser um verdeiro pesadelo ficar inserindo e apagando prints, e com debugging você pode, de fato explorar o código, linha a linha para saber o que está acontecendo, uma vez que este é um processo interativo.

Nenhum comentário:

Postar um comentário