Exercício – depurar com o Visual Studio Code
É hora de colocar em prática seus novos conhecimentos de depuração. É seu primeiro dia de trabalho, e chegou a hora de colocar suas habilidades de depuração do .NET em prática corrigindo um bug no principal produto da empresa, uma calculadora Fibonacci.
Criar um projeto .NET de exemplo para depuração
Para configurar o Visual Studio Code para depuração do .NET, primeiro precisamos de um projeto .NET. O Visual Studio Code inclui um terminal integrado, o que facilita a criação de projetos.
No Visual Studio Code, selecione Arquivo>Abrir pasta.
Crie uma pasta chamada
DotNetDebugging
no local de sua escolha. Depois clique em Selecionar Pasta.No Visual Studio Code, abra o terminal integrado selecionando Exibir>Terminal no menu principal.
Na janela do terminal, copie e cole o seguinte comando:
dotnet new console
Esse comando cria um arquivo Program.cs em sua pasta com um programa básico "Olá, Mundo" já escrito. Ele também cria um arquivo de projeto em C# chamado DotNetDebugging.csproj.
Na janela do terminal, copie e cole o seguinte comando para executar o programa "Olá, Mundo".
dotnet run
A janela do terminal exibe "Olá, Mundo!" como a saída.
Configurar o Visual Studio Code para a depuração do .NET
Selecione Program.cs para abri-lo.
Na primeira vez que você abrir um arquivo C# no Visual Studio Code, receberá um prompt para instalar as extensões recomendadas para o C#. Caso você veja esse prompt, selecione o botão Instalar.
O Visual Studio Code vai instalar a extensão C#, bem como exibir outro prompt para adicionar os ativos necessários a fim de criar e depurar o projeto. Selecione o botão Sim.
Você pode fechar a guia Extensão: C# para se concentrar no código que depuraremos.
Adicionar a lógica do programa Fibonacci
Nosso projeto atual escreve uma mensagem de "Olá, Mundo" no console, o que não oferece muito para depurar. Em vez disso, você usará um programa .NET curto para computar o enésimo número da sequência Fibonacci.
A sequência Fibonacci é um conjunto de números que começa com 0 e 1, em que cada número seguinte é a soma dos dois anteriores. A sequência continua conforme mostrado aqui:
0, 1, 1, 2, 3, 5, 8, 13, 21...
Selecione Program.cs para abri-lo.
Substitua o conteúdo do Program.cs pelo seguinte código:
int result = Fibonacci(5); Console.WriteLine(result); static int Fibonacci(int n) { int n1 = 0; int n2 = 1; int sum; for (int i = 2; i < n; i++) { sum = n1 + n2; n1 = n2; n2 = sum; } return n == 0 ? n1 : n2; }
Observação
Esse código contém um erro, que depuraremos posteriormente neste módulo. Não recomendamos o uso dele em nenhum aplicativo Fibonacci crítico até que o bug seja corrigido.
Salve o arquivo selecionando Ctrl+S no Windows e Linux. Selecione Cmd+S no Mac.
Daremos uma olhada de como o código atualizado funciona antes de depurá-lo. Execute o programa digitando o seguinte comando no terminal:
dotnet run
O resultado, 3, é mostrado na saída do terminal. Ao consultar este gráfico de sequência de Fibonacci que mostra a posição de sequência baseada em zero para cada valor entre parênteses, você verá que o resultado deveria ter sido 5. Chegou a hora de se familiarizar com o depurador e corrigir esse programa.
0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...
Analisar os problemas
Inicie o programa selecionando a guia Executar e Depurar, à esquerda, e depois selecione o botão Iniciar depuração. Talvez seja necessário selecionar primeiro o botão Executar e Depurar e selecionar o arquivo Program.cs.
Você verá o programa ser concluído rapidamente. Isso é normal porque você ainda não adicionou nenhum ponto de interrupção.
Se o console de depuração não aparecer, selecione Ctrl+Shift+Y no Windows e Linux ou Cmd+Shift+Y para Mac. Você deve ver várias linhas de informações de diagnóstico, com estas linhas no final:
... Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Threading.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Text.Encoding.Extensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 3 The program '[88820] DotNetDebugging.dll' has exited with code 0 (0x0).
As linhas na parte superior informam que as configurações de depuração padrão habilitam a opção "Apenas Meu Código". Isso significa que o depurador só depurará o código e não entrará no código-fonte do .NET, a menos que você desabilite esse modo. Essa opção permite que você se concentre na depuração do seu código.
No final da saída do console de depuração, você verá que o programa grava 3 no console e é encerrado com o código 0. Geralmente, o código de saída 0 indica que o programa foi executado e encerrado sem apresentar falhas. No entanto, há uma diferença entre apresentar falhas e retornar o valor correto. Neste caso, solicitamos que o programa calcule o quinto valor da sequência Fibonacci:
0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...
O quinto valor nessa lista é 5, mas o programa retornou 3. Vamos usar o depurador para diagnosticar e corrigir esse erro.
Usar pontos de interrupção e a execução passo a passo
Adicione um ponto de interrupção clicando na margem esquerda, na linha 1 em
int result = Fibonacci(5);
.Inicie a depuração novamente. O programa começa a ser executado. Ele é interrompido (a execução é pausada) na linha 1 devido ao ponto de interrupção que você definiu. Use os controles do depurador para entrar na função
Fibonacci()
.
Verificar estado das variáveis
Agora, dedique algum tempo para inspecionar os valores das diferentes variáveis usando o painel Variáveis.
- Qual é o valor mostrado para o parâmetro
n
? - No início da execução da função, quais são os valores das variáveis locais
n1
,n2
esum
?
Em seguida, vamos avançar para o loop
for
usando o controle do depurador Depuração Parcial.Continue avançando até atingir a primeira linha dentro do loop
for
, na linha em que está escrito:sum = n1 + n2;
Observação
Talvez você tenha observado que são necessários vários comandos de intervenção para percorrer a linha for(...) {}
. Isso ocorre porque há várias instruções nessa linha. Quando intervém, você passa para a instrução seguinte no código. Normalmente, há uma instrução por linha. Se não for esse o caso, você precisará de várias etapas para passar para a próxima linha.
Refletir sobre o código
Uma parte importante da depuração é parar e fazer suposições sobre o que você acha que as partes do código (funções e blocos, como os loops) estão tentando fazer. Não há problema se você não tem certeza, isso faz parte do processo de depuração. Mas ter um envolvimento ativo no processo de depuração ajudará a localizar bugs muito mais rapidamente.
Antes de continuar, precisamos nos lembrar de que a sequência Fibonacci é um conjunto de números que começa com 0 e 1, em que cada número seguinte é a soma dos dois anteriores.
Isso significa que:
Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1 (0 + 1)
Fibonacci(3) = 2 (1 + 1)
Fibonacci(4) = 3 (1 + 2)
Fibonacci(5) = 5 (2 + 3)
Após entender a definição e analisar o loop for
, podemos deduzir que:
- O loop conta de 2 até
n
(o número da sequência Fibonacci que estamos buscando). - Se
n
for menor que 2, o loop nunca será executado. A instruçãoreturn
no final da função retornará 0 sen
for 0 e 1 sen
for 1 ou 2. Esses são o valor zero e o primeiro e segundo valores na série Fibonacci, por definição. - O caso mais interessante é quando
n
é maior que 2. Nesses casos, o valor atual é definido como a soma dos dois valores anteriores. Portanto, para esse loop,n1
en2
são os dois valores anteriores, esum
é o valor para a iteração atual. Por isso, sempre que descobrimos a soma dos dois valores anteriores e a definimos comosum
, atualizamos nossos valoresn1
en2
.
Não precisamos pensar muito além disso. Podemos confiar um pouco em nosso depurador. Mas vale a pena pensar no código para ver se ele faz o que esperamos e ter mais informações quando isso não acontece.
Localizar o bug com pontos de interrupção
Percorrer o código possa ser útil, mas tedioso, especialmente quando se está trabalhando com loops ou outro código que é chamado repetidamente. Em vez de percorrer o loop repetidamente, podemos definir um novo ponto de interrupção na primeira linha do loop.
Durante esse processo, é importante inserir os pontos de interrupção de forma estratégica. Estamos especialmente interessados no valor de sum
, porque ele representa o valor máximo atual de Fibonacci. Por isso, colocaremos nosso ponto de interrupção na linha após a definição de sum
.
Adicione um segundo ponto de interrupção na linha 13.
Observação
Se você observar que continua executando o código e percorrendo uma linha ou duas, poderá facilmente atualizar seus pontos de interrupção para linhas mais eficientes.
Agora que temos um bom ponto de interrupção definido no loop, use o controle de depurador Continuar para avançar até que o ponto de interrupção seja atingido. Ao observarmos nossas variáveis locais, vemos as seguintes linhas:
n [int]: 5 n1 [int]: 0 n2 [int]: 1 sum [int]: 1 i [int]: 2
Todas essas linhas parecem corretas. Na primeira vez que o loop é executado, a
sum
dos dois valores anteriores é 1. Em vez de passar linha por linha, podemos aproveitar nossos pontos de interrupção para ir direto até a próxima execução do loop.Selecione Continuar para dar continuidade ao fluxo do programa até atingir o próximo ponto de interrupção, que estará na próxima passagem do loop.
Observação
Não se preocupe muito em relação a ignorar o bug ao usar Continuar. Depurar o código várias vezes para encontrar o problema é algo já esperado. Geralmente, o mais rápido é executá-lo algumas vezes, em vez de ser muito cauteloso ao percorrê-lo.
Desta vez, vemos os seguintes valores:
n [int]: 5 n1 [int]: 1 n2 [int]: 1 sum [int]: 2 i [int]: 3
Vamos pensar nisso. Esses valores ainda fazem sentido? Parece que sim. Para o terceiro número Fibonacci, esperamos ver nossa
sum
igual a 2, o que acontece.Ok, vamos selecionar Continuar para fazer um loop novamente.
n [int]: 5 n1 [int]: 1 n2 [int]: 2 sum [int]: 3 i [int]: 4
Mais uma vez, tudo parece bem. O quarto valor na série deve ser 3.
Neste momento, você pode se questionar se imaginou toda a situação do bug e se o código já estava certo desde o início. Vamos manter essa dúvida e executar o loop pela última vez. Selecione Continuar novamente.
Espere um pouco. O programa concluiu a execução e exibiu 3! Isso não está certo.
Não se preocupe. Nós não falhamos, nós aprendemos. Agora sabemos que o código executa o loop corretamente até que
i
seja igual a 4, mas ele é encerrado antes de calcular o valor final. Estou começando a ter algumas ideias sobre aonde o bug está. E você?Vamos definir mais um ponto de interrupção na linha 17, em que está escrito:
return n == 0 ? n1 : n2;
Esse ponto de interrupção nos permitirá inspecionar o estado do programa antes do encerramento da função. Já extraímos todas as informações necessárias usando os pontos de interrupção anteriores das linhas 1 e 13, então podemos limpá-los.
Remova os pontos de interrupção anteriores nas linhas 1 e 13. Você pode fazer isso clicando nelas na margem ao lado dos números de linha ou desmarcando as caixas de seleção de ponto de interrupção das linhas 1 e 13 no painel Pontos de interrupção no canto inferior esquerdo.
Agora que entendemos melhor o que está acontecendo e definimos um ponto de interrupção projetado para detectar o comportamento inadequado do programa, podemos identificar esse bug.
Inicie o depurador uma última vez.
n [int]: 5 n1 [int]: 2 n2 [int]: 3 sum [int]: 3
Isso não está correto. Solicitamos especificamente Fibonacci(5) e temos Fibonacci(4). Essa função retorna
n2
, e cada iteração de loop calcula o valor desum
e definen2
igual asum
.Com base nessas informações e em nossa execução de depuração anterior, podemos ver que o loop foi encerrado quando
i
era 4, e não 5.Vamos examinar a primeira linha do loop
for
um pouco melhor.for (int i = 2; i < n; i++)
Espere um pouco! Isso significa que ele será encerrado assim que a parte superior do loop vir que
i
já não é menor quen
. Isso significa que o código de loop não será executado casoi
seja igual an
. Parece que queríamos uma execução atéi <= n
, porém, em vez disso:for (int i = 2; i <= n; i++)
Com essa alteração, seu programa atualizado deve se parecer com este exemplo:
int result = Fibonacci(5); Console.WriteLine(result); static int Fibonacci(int n) { int n1 = 0; int n2 = 1; int sum; for (int i = 2; i <= n; i++) { sum = n1 + n2; n1 = n2; n2 = sum; } return n == 0 ? n1 : n2; }
Interrompa a sessão de depuração se ainda não tiver feito isso.
Em seguida, faça a alteração anterior na linha 10 e deixe nosso ponto de interrupção na linha 17.
Reinicie o depurador. Desta vez, quando atingirmos o ponto de interrupção na linha 17, veremos os seguintes valores:
n [int]: 5 n1 [int]: 3 n2 [int]: 5 sum [int]: 5
Ei! Parece que deu certo! Ótimo trabalho, você salvou o dia da Fibonacci, Inc.!
Selecione Continuar apenas para garantir que o programa retorne o valor correto.
5 The program '[105260] DotNetDebugging.dll' has exited with code 0 (0x0).
E ele retorna a saída certa.
Você conseguiu! Você depurou códigos que não escreveu, usando o depurador do .NET no Visual Studio Code.
Na próxima unidade, você verá como tornar o código escrito mais fácil de depurar, usando os recursos de registro em log e rastreamento integrados ao .NET.