Há uma verdade que todo curso deveria dizer cedo e com franqueza: você vai errar, muito, o tempo todo, e isso é absolutamente normal. Nenhum programador, por mais experiente, escreve programas não triviais sem cometer erros. A diferença entre o iniciante e o veterano não é que este último não erra — é que ele sabe encontrar e corrigir seus erros com rapidez e método. Essa habilidade, tão importante quanto escrever código, chama-se depuração (em inglês, debugging), e é o tema desta aula que fecha a Fase 2. Vamos entender os tipos de erro que existem, aprender a ler o que o computador nos diz sobre eles, e conhecer a técnica mais simples e universal para descobrir por que um programa não faz o que esperávamos. Encare os erros não como fracassos, mas como o diálogo natural entre você e a máquina.
A origem curiosa da palavra "bug"
Um erro em um programa é popularmente chamado de bug (em inglês, "inseto"), e o processo de eliminá-lo, de debugging ("desinsetização"). A origem do termo é célebre: em 1947, uma equipe que operava um dos primeiros computadores encontrou uma mariposa presa dentro da máquina, causando mau funcionamento; ao removê-la, anotaram que estavam "depurando" (debugging) o sistema, e colaram o inseto no relatório. A história, verdadeira ou embelezada, consagrou o vocabulário: até hoje, chamamos os erros de bugs e sua correção de depuração. Conto-a não como mera curiosidade, mas para desdramatizar o erro: ele é tão antigo quanto a própria computação, e faz parte do ofício desde o primeiro dia.
Os três tipos de erro
Nem todo erro é igual, e reconhecer o tipo de um erro é o primeiro passo para corrigi-lo. Há três categorias, e é útil distingui-las.
O primeiro é o erro de compilação (ou erro de sintaxe): você escreveu algo que o C# não consegue sequer entender — esqueceu um ponto e vírgula, digitou o nome de uma variável errado, deixou uma chave sem fechar. Esses erros são detectados antes de o programa rodar, quando você tenta compilá-lo (com dotnet run ou dotnet build), e são, paradoxalmente, os mais amigáveis: o compilador se recusa a construir o programa e lhe diz, com relativa precisão, o que está errado e onde. Um erro de compilação nunca chega ao usuário, porque o programa nem chega a rodar — ele é pego na sua tela, na hora.
O segundo é o erro de execução (em inglês, runtime error): o programa compila e começa a rodar, mas, durante a execução, encontra uma situação com a qual não sabe lidar e quebra. Você já viu um exemplo: usar int.Parse num texto que não é número. O programa não tinha erro de sintaxe — estava perfeitamente escrito —, mas, ao receber uma entrada inválida, encontrou um obstáculo insuperável e foi interrompido. Esses erros aparecem enquanto o programa roda, tipicamente com uma mensagem técnica descrevendo o que deu errado.
O terceiro, e mais insidioso, é o erro de lógica: o programa compila, roda até o fim sem quebrar, mas produz o resultado errado. Não há mensagem nenhuma — tudo parece funcionar —, exceto que a resposta está incorreta. Você calculou uma média e ela saiu absurda; classificou notas e o conceito veio trocado. O programa fez exatamente o que você mandou, mas o que você mandou não era o que você queria (lembra da primeira aula?). Esses são os erros mais difíceis de caçar, justamente porque o computador não o avisa — cabe a você perceber que o resultado está errado e investigar por quê. É para eles que a técnica que veremos a seguir é mais valiosa.
Lendo a mensagem de erro
Diante de um erro de compilação ou de execução, o computador lhe entrega uma mensagem de erro — e o instinto do iniciante é entrar em pânico e ignorá-la, tratando-a como um muro de texto assustador. Este é talvez o hábito mais prejudicial que você pode ter, e quero corrigi-lo agora: a mensagem de erro é sua melhor amiga, não sua inimiga. Ela existe para ajudá-lo, e frequentemente contém a solução, ou uma pista clara dela.
Ao ler uma mensagem de erro, procure três informações: onde o erro ocorreu (as mensagens costumam indicar o arquivo e o número da linha), o que deu errado (uma descrição, geralmente em inglês, do problema), e, quando for erro de compilação, um código do erro (algo como CS0103). Mesmo que a descrição esteja em inglês e você não a entenda por completo, o número da linha já o leva ao local do problema, e as palavras-chave da mensagem (por exemplo, "does not exist", "cannot convert", "expected") apontam a natureza dele. Se a mensagem ainda for obscura, copiá-la e pesquisá-la na internet quase sempre leva a explicações e soluções — programadores experientes fazem isso o tempo todo, sem vergonha alguma. Aprender a ler e a pesquisar mensagens de erro é uma das habilidades mais valiosas que você desenvolverá, e ela começa por não ignorá-las.
A técnica universal: exibir para investigar
Para os erros de lógica — aqueles em que o programa roda mas dá resposta errada —, não há mensagem para ler. Você precisa investigar o que está acontecendo dentro do programa enquanto ele roda. A técnica mais simples, universal e imediatamente disponível para isso é uma velha conhecida sua: o Console.WriteLine. A ideia é inserir exibições temporárias no código para espiar os valores das variáveis em pontos-chave, revelando onde a realidade diverge da sua expectativa.
Suponha que você escreveu um cálculo de média que está dando resultado errado:
int nota1 = 8;
int nota2 = 6;
int nota3 = 7;
int media = nota1 + nota2 + nota3 / 3; // resultado errado!
Console.WriteLine($"A média é {media}"); // exibe 16, e não 7 — algo está errado
O resultado saiu 16, quando esperávamos 7. Para investigar, inserimos exibições que revelam os valores intermediários:
Console.WriteLine($"Soma das notas: {nota1 + nota2 + nota3}"); // exibe 21, correto
Console.WriteLine($"nota3 / 3 vale: {nota3 / 3}"); // exibe 2 — reveladora!
A segunda exibição é a chave: ela revela que nota3 / 3 vale 2, o que expõe o problema. Lembrando a ordem das operações (Aula #06), a divisão acontece antes da soma, então nota1 + nota2 + nota3 / 3 foi calculado como 8 + 6 + (7/3) = 8 + 6 + 2 = 16, e não como a média que queríamos. O erro de lógica estava na falta de parênteses, e a exibição temporária o revelou. A correção é (nota1 + nota2 + nota3) / 3. Este é o método: quando o resultado surpreende, espie os valores pelo caminho com Console.WriteLine, comparando o que você vê com o que esperava; a divergência aponta o erro. Depois de corrigir, remova as exibições temporárias.
Uma nota sobre ferramentas de depuração
Vale mencionar que editores como o VS Code oferecem ferramentas de depuração muito mais poderosas que o Console.WriteLine — recursos que permitem pausar o programa em um ponto e inspecionar todas as variáveis, executar linha a linha, e observar o fluxo em detalhe (os chamados pontos de interrupção, ou breakpoints). Essas ferramentas são valiosas e você as aprenderá com o tempo. Mas menciono-as por completude, não como prioridade agora: para um iniciante, a técnica simples do Console.WriteLine é suficiente, universal e imediatamente compreensível, e resolve a grande maioria dos casos. Domine primeiro o método simples; as ferramentas avançadas virão quando você sentir necessidade delas.
Encerrando a Fase 2
Com esta aula, fecha-se a segunda fase da sua jornada. Você começou a fase com programas que só executavam em linha reta; termina-a com programas que decidem (if, switch), repetem (while, for, foreach), e — tão importante quanto — com a capacidade de encontrar e corrigir os erros que inevitavelmente cometerá. Essa última habilidade, a depuração, não é um apêndice: é o que torna todas as outras utilizáveis na prática, pois programar de verdade é um ciclo constante de escrever, errar, investigar e corrigir. Abrace esse ciclo; ele é o coração do ofício.
Errar deixou de ser um acidente e passou a ser parte do método. Você distingue agora os três tipos de erro: o de compilação, que impede o programa de rodar; o de execução, que o interrompe no meio; e o lógico, o mais traiçoeiro, em que tudo roda mas o resultado está errado.
A mensagem de erro deixou de ser ruído. Ela informa o arquivo, a linha e a natureza do problema, e lê-la com atenção costuma resolver em segundos o que adivinhar levaria muito tempo. Somada à técnica universal de exibir valores intermediários para investigar, ela dá autonomia real diante de um defeito. Nenhum programador escreve código certo de primeira; a diferença está em saber investigar.
Fontes e leituras recomendadas
- Depuração no Visual Studio Code — o guia oficial das ferramentas de depuração do editor, para quando você quiser ir além do
Console.WriteLine. - Tipos de erros de compilação em C# — a referência das mensagens do compilador, útil para decifrar erros de compilação.
- Tratamento e diagnóstico de erros — o panorama de como erros surgem e são reportados em C#.
- A história do primeiro "bug" — o relato histórico da mariposa que deu nome aos erros de programação.
- Como fazer boas perguntas técnicas — um guia sobre pesquisar e pedir ajuda com erros de forma eficaz, habilidade essencial do programador.
Exercícios
Exercício 1
Classifique cada uma das seguintes situações como erro de compilação, de execução ou de lógica: (a) você esqueceu um ponto e vírgula e o programa não compila; (b) o programa calcula uma média mas dá um valor absurdo, sem quebrar; (c) o programa quebra ao tentar converter "abc" em número com int.Parse. Justifique cada classificação.
Ver resposta
✓ Resposta: (a) Erro de compilação: um ponto e vírgula faltando é um erro de sintaxe, detectado antes de o programa rodar, impedindo a compilação. (b) Erro de lógica: o programa roda até o fim sem quebrar, mas produz um resultado incorreto — não há mensagem, apenas uma resposta errada, o que caracteriza o erro de lógica. (c) Erro de execução: o programa está sintaticamente correto e começa a rodar, mas quebra durante a execução ao encontrar uma situação insuperável (converter texto inválido em número), que é um erro de tempo de execução.
Exercício 2
Provoque deliberadamente um erro de compilação (por exemplo, escreva Console.WriteLine(mensagem) sem ter declarado a variável mensagem), tente rodar, e leia a mensagem de erro. Anote: em que linha o erro foi apontado, e quais palavras-chave da mensagem indicam a natureza do problema?
Ver resposta
✓ Resposta: Ao escrever Console.WriteLine(mensagem) sem declarar mensagem e tentar rodar, o compilador aponta um erro na linha em questão (o número exato depende de onde você a escreveu), com uma descrição como "The name 'mensagem' does not exist in the current context" e um código como CS0103. As palavras-chave "does not exist" indicam a natureza do problema: o compilador não conhece nenhuma variável com esse nome, porque ela nunca foi declarada. O número da linha leva diretamente ao local do erro.
Exercício 3
Escreva um programa que calcule a média de três notas com o erro de parênteses mostrado na aula (nota1 + nota2 + nota3 / 3). Depois, use exibições temporárias com Console.WriteLine para investigar por que o resultado está errado, identifique a causa, e corrija-a. Descreva o que cada exibição revelou.
Ver resposta
✓ Resposta: Exemplo:
int nota1 = 8, nota2 = 6, nota3 = 7;
int media = nota1 + nota2 + nota3 / 3;
Console.WriteLine($"Média (errada): {media}"); // 16
Console.WriteLine($"Soma correta: {nota1 + nota2 + nota3}"); // 21
Console.WriteLine($"nota3 / 3 vale: {nota3 / 3}"); // 2
As exibições revelam que a soma das três notas é 21 (correta), mas nota3 / 3 vale 2 — mostrando que a divisão foi aplicada só à nota3, antes da soma, por causa da ordem das operações. A causa é a falta de parênteses; a correção é (nota1 + nota2 + nota3) / 3, que dá 7. Cada exibição intermediária estreitou a busca até localizar exatamente onde o cálculo divergiu do esperado.
Exercício 4
Explique, com suas palavras, por que os erros de lógica são geralmente mais difíceis de encontrar do que os erros de compilação. O que os erros de compilação têm que os de lógica não têm, e que facilita sua correção?
Ver resposta
✓ Resposta: Os erros de lógica são mais difíceis de encontrar porque o computador não os sinaliza: o programa compila e roda até o fim sem quebrar, produzindo um resultado que parece normal mas está incorreto — cabe inteiramente a você perceber que a resposta está errada e investigar a causa. Os erros de compilação, ao contrário, têm uma mensagem: o compilador recusa o programa e informa o local (a linha) e a natureza do problema, apontando diretamente para onde olhar. É essa sinalização explícita que os de compilação têm e os de lógica não, o que torna os primeiros muito mais fáceis de corrigir.
Exercício 5
Sem código: um colega iniciante diz que, quando vê uma mensagem de erro, ele simplesmente apaga a última coisa que escreveu e tenta outra coisa ao acaso, sem ler a mensagem. Explique por que essa abordagem é ineficiente e o que ele deveria fazer em vez disso.
Ver resposta
✓ Resposta: Essa abordagem é ineficiente porque ignora a informação mais útil disponível: a própria mensagem de erro, que costuma indicar onde e o que está errado, muitas vezes apontando direto para a solução. Apagar coisas ao acaso e tentar de novo é um método cego, lento e que pode até introduzir novos erros, sem ensinar nada sobre a causa real. Em vez disso, ele deveria ler a mensagem com atenção — identificar a linha indicada, as palavras-chave que descrevem o problema — e, se ainda não entender, pesquisar a mensagem na internet. Tratar a mensagem de erro como uma aliada que aponta o caminho é muito mais rápido e, além disso, ensina a evitar o mesmo erro no futuro.