Exercício – depurar com o Visual Studio Code

Concluído

É hora de colocar em prática seus novos conhecimentos de depuração. Acontece que temos a oportunidade perfeita. Em nosso aplicativo da Tailwind Traders, estamos desenvolvendo um novo recurso para permitir a exibição do preço de um produto em várias moedas. Um colega de trabalho escreveu um pouco de código, mas está com dificuldades para descobrir o que está dando errado. Vamos ajudar.

Criar um arquivo JavaScript em um workspace do Visual Studio

Para este exercício, você precisa de um arquivo JavaScript para praticar a depuração. Para usar os controles de inicialização do depurador, o arquivo JavaScript precisa estar em um workspace do Visual Studio.

O objetivo do aplicativo é definir a taxa de câmbio entre três moedas: USD, EUR e JPY. Em seguida, queremos exibir qual é o valor de 10 EUR nas outras moedas usando dois dígitos após a casa decimal. Para cada moeda adicionada, a taxa de câmbio para todas as outras moedas deve ser calculada.

  1. No Visual Studio Code, crie um arquivo chamado mycurrency.js na subpasta ./nodejs-debug/.

  2. Cole o seguinte código no editor do novo arquivo:

    const rates = {};
    
    function setExchangeRate(rate, sourceCurrency, targetCurrency) {
      if (rates[sourceCurrency] === undefined) {
        rates[sourceCurrency] = {};
      }
    
      if (rates[targetCurrency] === undefined) {
        rates[targetCurrency] = {};
      }
    
      rates[sourceCurrency][targetCurrency] = rate;
      rates[targetCurrency][sourceCurrency] = 1 / rate;
    }
    
    function convertToCurrency(value, sourceCurrency, targetCurrency) {
      const exchangeRate = rates[sourceCurrency][targetCurrency];
      return exchangeRate && value * exchangeRate;
    }
    
    function formatValueForDisplay(value) {
      return value.toFixed(2);
    }
    
    function printForeignValues(value, sourceCurrency) {
      console.info(`The value of ${value} ${sourceCurrency} is:`);
    
      for (const targetCurrency in rates) {
        if (targetCurrency !== sourceCurrency) {
          const convertedValue = convertToCurrency(value, sourceCurrency, targetCurrency);
          const displayValue = formatValueForDisplay(convertedValue);
          console.info(`- ${convertedValue} ${targetCurrency}`);
        }
      }
    }
    
    setExchangeRate(0.88, 'USD', 'EUR');
    setExchangeRate(107.4, 'USD', 'JPY');
    printForeignValues(10, 'EUR');
    
  3. Para salvar o arquivo, pressione Ctrl+S (Windows, Linux) ou Cmd+S (Mac).

Criar uma configuração de inicialização

Vamos usar muito o depurador, portanto, vamos criar uma configuração de inicialização para o aplicativo.

  1. Na guia Executar no Visual Studio Code, selecione Criar um arquivo launch.json e selecione o depurador do Node.js.

    O Visual Studio Code cria o arquivo de configuração .vscode/launch.json na raiz do workspace e abre o arquivo de inicialização para edição.

    Screenshot of generated launch configuration.

    Por padrão, é criada uma configuração de inicialização para executar o arquivo aberto no momento. Nesse exemplo, o arquivo aberto é mycurrency.js. Você pode modificar a configuração de inicialização para personalizar como o programa deve ser iniciado durante a depuração.

  2. Na configuração de inicialização, exiba o valor da propriedade program.

    {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                "type": "node",
                "request": "launch",
                "name": "Launch Program",
                "skipFiles": [
                    "<node_internals>/**"
                ],
                "program": "${workspaceFolder}/nodejs-debug/mycurrency.js"
            }
        ]
    }
    
    • ${workspaceFolder} indica a raiz do workspace.
  3. Feche o arquivo .vscode/launch.json.

Observação

Você pode criar diferentes configurações de inicialização para o projeto selecionando Adicionar Configuração no canto inferior direito.

Analisar os problemas

Verifique se o ambiente do Visual Studio Code está pronto para monitorar o processo de depuração:

  • O painel do depurador deve ser aberto à esquerda. Use o ícone na guia Executar à esquerda para alternar a visibilidade do painel.
  • O console de depuração deve ser aberto na parte inferior. Abra o console selecionando Exibir>Console de Depuração ou pressionando Ctrl+Shift+Y (Windows, Linux) ou Cmd+Shift+Y (Mac).

Agora, você já pode começar a depuração.

Nos controles de inicialização do depurador, inicie o programa com a depuração habilitada (a seta verde).

Screenshot of the Start debugging button in Visual Studio Code.

Você verá o programa ser concluído rapidamente. Isso é normal porque você ainda não adicionou nenhum ponto de interrupção.

Você deverá ver este texto no console de depuração, seguido por uma exceção.

The value of 10 EUR is:
11.363636363636365
- 11.363636363636365 USD
/app/node-101/currency.js:23
  return value.toFixed(2);
               ^
TypeError: Cannot read property 'toFixed' of undefined
    at formatValueForDisplay (/app/node-101/currency.js:23:16)
    at printForeignValues (/app/node-101/currency.js:32:28)
    at Object.<anonymous> (/app/node-101/currency.js:40:1)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
    at internal/main/run_main_module.js:17:11

O objetivo deste programa é definir a taxa de câmbio entre três moedas (USD, EUR, JPY) e exibir qual o valor de 10 EUR em todas as outras moedas, com dois dígitos após uma casa decimal.

Podemos ver dois bugs aqui:

  • Há mais de dois dígitos após a casa decimal.
  • O programa falhou com uma exceção e não exibiu o valor de JPY.

Dica

  • Defina "outputCapture": "std", em seu arquivo de configuração de inicialização para aumentar a saída do registro em log.
  • Defina um logpoint em vez de um ponto de interrupção para evitar interromper a execução do programa. Um logpoint não "interrompe" o depurador, mas, em vez disso, registra uma mensagem no console. Os logpoints são especialmente úteis para injetar log durante a depuração de servidores de produção que não podem ser pausados ou interrompidos.

Corrigir a exibição de dígitos

Começaremos com a correção do primeiro bug. Como você não escreveu esse código e funções diferentes estão sendo chamadas, vamos entender primeiro o fluxo de execução usando a execução passo a passo.

Usar pontos de interrupção e a execução passo a passo

Para adicionar um ponto de interrupção, selecione a linha 39 na margem esquerda, em printForeignValues(10, 'EUR');.

Screenshot of the breakpoint location in the code.

Inicie a depuração novamente e intervenha na função printForeignValues() com o controle de depuração Intervir:

Screenshot of the Step into button.

Verificar estado das variáveis

Agora, dedique algum tempo a inspecionar os diferentes valores das variáveis no painel Variáveis.

Screenshot of the Variables pane.

  • Quais são os valores das variáveis value e sourceCurrency?
  • Para a variável rates, você vê as três chaves esperadas USD, EUR e JPY?

Para avançar passo a passo até que a variável convertedValue seja definida, use o controle de depuração Contornar:

Screenshot of the Step over button.

Após usar o controle Contornar cinco vezes, você deverá ver o valor da variável convertedValue definido como o 11.363636363636365 esperado.

Se contornarmos mais uma vez, veremos o valor da variável displayValue. O valor deve ser a cadeia de caracteres formatada para exibição com dois dígitos 11.36.

Podemos, então, concluir que até este ponto no programa, as funções convertToCurrency() e formatValueForDisplay() parecem corretas e retornam o resultado esperado.

Corrigir o erro

Use o controle Intervir uma vez para chegar à chamada à função console.info(). Examine essa linha de código atentamente. Você vê o erro aqui?

Precisamos corrigir o bug do programa usando a variável displayValue em vez da variável convertedValue para imprimir o valor.

  1. Atualize o arquivo currency.js para usar o nome correto da variável. Altere a chamada à função console.info() na linha 32 para usar a variável displayValue em vez da variável convertedValue:

    console.info(`- ${displayValue} ${targetCurrency}`);
    
  2. Salve as alterações no arquivo.

  3. Reinicie o programa.

Verifique se o programa exibe corretamente o valor USD como 11.36. Primeiro bug: corrigido.

Encontrar a causa da falha

Agora, vamos descobrir por que o programa está falhando.

  1. No arquivo currency.js, remova o ponto de interrupção definido na linha 39.

  2. Para forçar o programa a pausar após a exceção ser gerada, no painel Pontos de interrupção, marque a caixa Exceção Não Capturada.

  3. Execute o programa no depurador novamente.

O programa deve pausar na exceção e mostrar um relatório de erros grande no meio da janela do editor.

Screenshot of the exception message shown in Visual Studio Code.

Examine a linha em que a execução foi interrompida e observe a mensagem de exceção TypeError: Cannot read property 'toFixed' of undefined. Com essa mensagem, você pode deduzir que a função de parâmetro value tem o valor undefined em vez de um número. Esse erro causou a exceção.

Retroceder a pilha de chamadas

O rastreamento de pilha que você vê abaixo da mensagem de erro pode ser um pouco difícil de decifrar. A boa notícia é que Visual Studio Code processa a pilha de chamadas de função para você. Por padrão, ele mostra apenas as informações significativas no painel Pilha de chamadas. Vamos usar informações da pilha de chamadas para localizar o código que levou a essa exceção.

Sabemos que a exceção foi lançada na chamada à função formatValueForDisplay().

  1. No painel do depurador, vá até o painel Pilha de chamadas.

  2. Para ver onde a função formatValueForDisplay() foi chamada, clique duas vezes na função abaixo dela; a função printForeignValues.

    O Visual Studio Code vai até a linha na função printForeignValues em seu arquivo currency.js, em que a função formatValueForDisplay() foi chamada:

    const displayValue = formatValueForDisplay(convertedValue);
    

Examine atentamente esta linha de código. O parâmetro que está causando a exceção é proveniente da variável convertedValue. Você precisa descobrir em que ponto o valor desse parâmetro se torna undefined.

Uma opção é adicionar um ponto de interrupção nessa linha e, então, inspecionar a variável sempre que o ponto de interrupção parar na linha. No entanto, não sabemos quando o valor errado pode ocorrer e, em programas complexos, essa abordagem de depuração pode ser complicada. Vamos examinar um método alternativo.

Adicionar um ponto de interrupção condicional

Em nosso caso, seria útil fazer com que o depurador parasse neste ponto de interrupção somente quando o valor da variável convertedValue fosse undefined. Felizmente, o Visual Studio Code pode fazer isso usando as opções corretas de clique com o mouse.

  1. No arquivo currency.js, na margem esquerda na linha 31, clique com o botão direito do mouse e selecione Adicionar Ponto de Interrupção Condicional.

    Screenshot of setting a conditional breakpoint in Visual Studio Code.

  2. Após clicar com o botão direito do mouse, insira a seguinte condição para disparar o ponto de interrupção e pressione Enter:

    `convertedValue === undefined`
    
  3. Reinicie o programa.

Agora, o programa deve parar na linha 31 e podemos examinar os valores da pilha de chamadas.

Observar o estado atual

Vamos dedicar algum tempo a analisar o estado do programa atual.

  • O valor da variável convertedValue vem da chamada à função convertToCurrency(value, sourceCurrency, targetCurrency). Precisamos verificar os valores de parâmetro nesta chamada de função e confirmar se estão corretos.

  • Especificamente, precisamos examinar a variável value e confirmar que ela tem o valor esperado 10.

Dê uma olhada no código da função convertToCurrency().

function convertToCurrency(value, sourceCurrency, targetCurrency) {
  const exchangeRate = rates[sourceCurrency][targetCurrency];
  return exchangeRate && value * exchangeRate;
}

Você sabe que o resultado desse código é undefined. Você também sabe que a variável value está definida como 10. Essas informações nos ajudam a ver que o problema deve estar no valor da variável exchangeRate.

No arquivo currency.js, passe o mouse sobre a variável rates para dar uma olhada:

Screenshot of peeking at the rates variable value.

Você tenta obter a taxa de câmbio de EUR para JPY, mas se desdobrar o valor EUR, verá que há apenas uma taxa de conversão para USD. A taxa de conversão para JPY está ausente.

Corrigir taxas de conversão ausentes

Agora que você sabe que algumas taxas de conversão estão ausentes, vamos entender o porquê. Para remover todos os pontos de interrupção existentes, no painel Pontos de Interrupção, selecione o ícone Remover todos os pontos de interrupção.

Screenshot of the button to remove all breakpoints.

Inspecionar a variável rates

Vamos definir um ponto de interrupção para inspecionar a variável rates.

  1. No arquivo currency.js, adicione um ponto de interrupção na linha 37 na função setExchangeRate(0.88, 'USD', 'EUR');.

  2. No painel Inspeção, selecione Mais e insira rates.

    Sempre que o valor da variável rates é alterado, o valor atualizado é mostrado no painel Inspeção.

  3. Reinicie o programa.

  4. Quando o ponto de interrupção parar na primeira chamada à função setExchangeRate(), use o controle Contornar.

  5. No painel Inspeção, examine o valor da variável rates.

    Neste ponto, USD e EUR têm taxas de conversão opostas correspondentes, como esperado.

  6. Contorne novamente na segunda chamada para a função setExchangeRate().

    Você vê que USD e JPY têm taxas de conversão opostas correspondentes, mas não há nada entre EUR e JPY.

É hora de examinar o código para a função setExchangeRate().

function setExchangeRate(rate, sourceCurrency, targetCurrency) {
  if (rates[sourceCurrency] === undefined) {
    rates[sourceCurrency] = {};
  }

  if (rates[targetCurrency] === undefined) {
    rates[targetCurrency] = {};
  }

  rates[sourceCurrency][targetCurrency] = rate;
  rates[targetCurrency][sourceCurrency] = 1 / rate;
}

As linhas mais importantes nesta função são as duas últimas. Parece que você encontrou o segundo bug! As taxas de conversão são definidas apenas entre as variáveis sourceCurrency e targetCurrency. O programa também precisa calcular a taxa de conversão para as outras moedas adicionadas.

Corrigir o código

Vamos corrigir o código para o problema da taxa de conversão.

  1. Atualize seu arquivo currency.js para calcular a taxa de conversão das outras moedas.

    Substitua o código nas linhas 12 e 13:

    rates[sourceCurrency][targetCurrency] = rate;
    rates[targetCurrency][sourceCurrency] = 1 / rate;
    

    por este código atualizado:

    for (const currency in rates) {
      if (currency !== targetCurrency) {
        // Use a pivot rate for currencies that don't have the direct conversion rate
        const pivotRate = currency === sourceCurrency ? 1 : rates[currency][sourceCurrency];
        rates[currency][targetCurrency] = rate * pivotRate;
        rates[targetCurrency][currency] = 1 / (rate * pivotRate);
      }
    }
    
  2. Salve as alterações no arquivo.

O código atualizado define a taxa de conversão de qualquer outra moeda diferente de sourceCurrency e targetCurrency. O programa usa a taxa de conversão de sourceCurrency para deduzir a taxa entre a outra moeda e targetCurrency. Em seguida, o código define a taxa de conversão para a outra moeda adequadamente.

Observação

Essa correção só funcionará se as taxas entre sourceCurrency e as outras moedas já existirem, o que é uma limitação aceitável nesse caso.

Testar a correção

Vamos testar nossa alteração.

  1. Remova todos os pontos de interrupção e inspecione as variáveis.

  2. Reinicie o programa.

Agora você deverá ver o resultado esperado no console, sem nenhuma falha.

The value of 10 EUR is:
- 11.36 USD
- 1220.45 JPY

É isso. Você corrigiu o código. Agora você pode depurar com eficiência códigos desconhecidos com antecedência usando o Visual Studio Code. Muito bem!

Limpar o contêiner de desenvolvimento

Depois de concluir o projeto, limpe o ambiente de desenvolvimento ou devolva-o ao estado padrão.

A exclusão do ambiente GitHub Codespaces garante que você possa maximizar a quantidade de horas gratuitas por núcleo que você tem direito na sua conta.

Importante

Para saber mais sobre os direitos da sua conta do GitHub, confira O GitHub Codespaces inclui mensalmente armazenamento e horas de núcleo.

  1. Entre no painel do GitHub Codespaces (https://github.com/codespaces).

  2. Localize seus Codespaces atualmente em execução, originados do repositório MicrosoftDocs/node-essentials do GitHub.

    Screenshot of all the running Codespaces including their status and templates.

  3. Abra o menu de contexto do codespace e selecione Excluir.

    Screenshot of the context menu for a single codespace with the delete option highlighted.