Este é o vigésimo sexto de uma série de posts que estou escrevendo sobre o próximo lançamento do VS 2010 e .NET 4.
O post de hoje aborda algumas dicas de depuração de código úteis que você pode usar com o Visual Studio. Meu amigo Scott Cate (que já escreveu dezenas de ótimas dicas e truques do VS aqui
[em Inglês]) recentemente destacou as mesmas para mim como boas dicas
que a maioria dos desenvolvedores que usam o Visual Studio parecem não
ter conhecimento (apesar da maioria já estar presente no produto há algum
tempo). Esperançosamente este post o ajudará a descobri-las se você
ainda não estiver tirando vantagem delas. Elas são fáceis de aprender, e
podem ajudar você a economizar bastante tempo.
Executar Até o Cursor (Ctrl + F10)
Muitas
vezes vejo pessoas depurando aplicações atingindo um breakpoint (ponto
de interrupção) no início da aplicação e, em seguida, a pessoa
repetidamente usa as teclas F10/F11 para percorrer o código até chegar ao local
específico que ela realmente quer investigar. Em alguns casos, elas
estão observando cuidadosamente cada instrução ao longo do caminho
(neste caso, usar F10/F11 faz sentido). Muitas vezes, porém, as pessoas
estão apenas tentando avançar rapidamente para a linha de código que
elas realmente estão interessadas - e nesse caso usando F10/F11 não é a
melhor maneira de fazer isso.
Ao invés disso, você pode querer
tirar proveito do recurso "Run to Cursos" (Executar Até o Cursor) que o
debugger (depurador) suporta. Basta posicionar o cursor do teclado na linha do seu
código que você deseja que a aplicação execute e, em seguida pressione
as teclas Ctrl + F10 juntas. Isto irá executar a aplicação até a
localização da linha e, em seguida, interromperá o depurador -
poupando-o de ter de apertar várias vezes as teclas F10/F11 para chegar
lá. Isso funciona mesmo se a linha de código que você pretende executar
estiver em um método ou uma classe separada daquela que você está
atualmente depurando.
Breakpoints Condicionais
Outra
coisa comum que frequente vemos em estudos de usabilidade são os casos
onde os desenvolvedores definem breakpoints, executam a aplicação,
tentam alguns valores de entrada, atingem um breakpoint, e manualmente
verificam se alguma condição é true (verdadeira), antes de decidir se
investigam mais ou não. Se o cenário não corresponde ao que eles estão
interessados, eles pressionam a tecla F5 para continuar a execução da aplicação,
tentam outros valores de entrada, e repetem o processo manualmente.
Os
breakpoints condicionais do Visual Studio fornecem uma maneira muito,
muito mais fácil para lidar com esse tipo de situação. Os breakpoints
condicionais permitem que você interrompa o depurador somente se alguma
condição específica que você setar seja atingida. Eles ajudam você a
evitar a inspeção manual/re-execução de sua aplicação, e tornam todo o
processo de depuração muito menos manual e tedioso.
Como Habilitar um Breakpoint Condicional
Configurar
um breakpoint condicional é realmente fácil. Pressione a tecla F9 no seu
código para definir um breakpoint em uma linha específica:
Então
clique com o botão direito do mouse no "círculo vermelho", à esquerda
do editor e selecione a opção "Condition..." (Condição) no menu de contexto:
Isso
abrirá uma janela de diálogo que te permite indicar que o breakpoint só
deve ser atingido, se alguma condição for verdadeira. Por exemplo,
podemos indicar que só queremos interromper o depurador se o tamanho da
lista local paginatedDinners for inferior a 10 escrevendo a expressão de
código a seguir:
Agora,
quando eu re-executar a aplicação e fizer uma pesquisa, o depurador
somente será interrompido se eu realizar uma pesquisa que retorne menos
de 10 dinners (jantares). Se houver mais de 10 jantares, o breakpoint
não será atingido.
Recurso Hit Count (Contagem de Hits)
Às
vezes você só quer interromper a execução da aplicação em uma condição
na qual a enésima vez é verdadeira. Por exemplo: somente interromper a
aplicação na quinta vez em que menos de 10 jantares forem retornados em
uma pesquisa.
Você pode ativar este recurso clicando com o botão
direito do mouse em um breakpoint e selecionando o comando do menu de
contexto "Hit count...".
Isso
abrirá uma janela de diálogo que lhe permite indicar que o breakpoint
somente será atingido na enésima vez que uma condição for atendida, ou a
cada N vezes que a condição for verdadeira, ou toda vez após N
ocorrências:
Filtragem por Máquina/Thread/Processo
Você
também pode clicar com o botão direito do mouse em um breakpoint e
selecionar a opção "Filter..." (Filtro) no menu de contexto para indicar
que um breakpoint deve somente ser atingido se o mesmo ocorrer em uma
máquina específica, ou em um processo específico, ou em uma thread
específica.
TracePoints (Pontos de Rastreamento) - Ações Personalizadas Quando Um BreakPoint For Atingido
Um recurso de depuração que muita gente não conhece é a capacidade de usar TracePoints
(em Inglês). Um TracePoint é um breakpoint que possui uma ação
personalizada que é disparada quando o breakpoint é atingido. Este
recurso é particularmente útil quando você quer observar comportamento
dentro de sua aplicação, sem interromper o processo de depuração.
Vou
usar uma simples aplicação Console para demonstrar como podemos ser
capazes de tirar proveito dos TracePoints. A seguir está uma
implementação recursiva da sequência de Fibonacci:
Na
aplicação acima, estamos usando Console.WriteLine() para escrever o
valor final da seqüência de Fibonacci para um valor de entrada
específico. O que aconteceria se quissemos observar a sequência
recursiva de Fibonacci em ação ao longo do processo dentro do depurador -
sem realmente interromper a execução da aplicação? TracePoints podem
nos ajudar a fazer isso facilmente.
Configurando um TracePoint
Você
pode ativar um TracePoint usando a tecla F9 para definir um breakpoint
em uma linha de código, e em seguida clicar com o botão direito do mouse
no breakpoint e escolher a opção "When Hit..."(Quando Atingido...) no
menu de contexto:
Isso
fará com que a seguinte janela de diálogo apareça - a qual te permite
especificar o que deve acontecer quando o breakpoint for atingido:
Acima,
nós especificamos que queremos imprimir uma mensagem de rastreamento a
qualquer momento em que a condição do breakpoint for
atendida/verdadeira. Observe que nós especificamos que queremos
imprimir o valor da variável local "x" como parte da mensagem. As
variáveis locais podem ser referenciadas usando a sintaxe
{nomeDaVariavel}. Há também comandos nativos (como $CALLER, $CALLSTACK,
$FUNCTION, etc) que podem ser utilizados para imprimir valores de saída
comuns dentro de suas mensagens de rastreamento.
Acima nós
também marcamos a caixa de seleção "continue execution" (continuar a
execução) na parte inferior da janela - o que indica que não
queremos que a aplicação seja interrompida pelo depurador. Ao invés
disso, continuaremos executando a aplicação - a única diferença é que a
nossa mensagem de rastreamento customizada será mostrada na tela a cada
vez em que a condição do breakpoint for atendida.
E agora,
quando executarmos a aplicação, veremos que nossas mensagens de
rastreamento customizadas aparecerão automaticamente na janela de
"output" (saída) do Visual Studio - o que nos permite acompanhar o
comportamento recursivo da aplicação:
Você
pode, alternativamente, acoplar um rastreador ouvinte customizado em
sua aplicação - caso em que as mensagens que você imprimir a partir dos
TracePoints serão encaminhadas a ele, ao invés de serem enviadas para a
janela de saída do VS.
TracePoints - Executando uma Macro Customizada
Em
uma palestra que dei semana passada em Londres, alguém na plateia
perguntou se era possível imprimir o valor de todas as variáveis locais
quando um TracePoint fosse atingido.
Esse recurso não é nativo
no Visual Studio - mas pode ser ativado ao escrevermos uma macro no
Visual Studio e, em seguida configurando um Tracepoint para chamar a
macro quando este for atingido. Para permitir isso, abra o IDE de
Macros no Visual Studio (Ferramentas->Macros->IDE para Macros). Em seguida, sob o nó MyMacros (Minhas Macros) no Project Explorer,
selecione um módulo ou crie um novo (por exemplo: adicione um chamado
"UsefulThings" [CoisasUteis]). Em seguida, cole o seguinte código de
macro VB no módulo e salve o mesmo:
Sub DumpLocals()
Dim outputWindow As EnvDTE.OutputWindow
outputWindow = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Object
Dim currentStackFrame As EnvDTE.StackFrame
currentStackFrame = DTE.Debugger.CurrentStackFrame
outputWindow.ActivePane.OutputString("*Dumping Local Variables*" + vbCrLf)
For Each exp As EnvDTE.Expression In currentStackFrame.Locals
outputWindow.ActivePane.OutputString(exp.Name + " = " + exp.Value.ToString() + vbCrLf)
Next
End Sub
O código de macro acima percorre o quadro atual da pilha e despeja todas as variáveis locais na janela de saída.
Usando nossa Macro DumpLocals customizada
Podemos, então, aproveitar a nossa macro "DumpLocals" customizada utilizando a aplicação de uma simples adição como a seguir:
Usaremos
a tecla F9 para definir um breakpoint na instrução de retorno dentro
do nosso método "Add" mostrado acima. Vamos, então, clicar com o
botão direito do mouse no breakpoint e selecionar a opção "When Hit..."
no menu de contexto:
Isso
abrirá a janela de diálogo a seguir. Ao contrário de antes, onde
usamos a opção da caixa de seleção "Print a message" (Imprimir uma
mensagem) e manualmente especificamos as variáveis que queríamos na
saída, desta vez nós vamos selecionar a opção da caixa de seleção "Run a
macro" (Executar uma macro) e apontaremos para a macro customizada
UsefulThings.DumpLocals que criamos acima:
Vamos
manter a caixa de seleção "Continue execution" selecionada de modo que o
programa continuará rodando, até mesmo quando os nossos TracePoints forem
atingidos.
Executando a Aplicação
E agora, quando
nós pressionamos a tecla F5 e executamos a aplicação, veremos o seguinte
resultado aparecer na janela de saída do Visual Studio quando o nosso
método Add for chamado. Observe como a macro está listando
automaticamente o nome e o valor de cada variável local quando o
TracePoint é atingido:
Resumo
O
depurador de código do Visual Studio é incrivelmente rico. Eu
recomendo que você separe algum tempo para realmente aprender todos os
seus recursos. As dicas e truques acima são apenas algumas dos muitos
recursos que o depurador oferece e que a maioria das pessoas
desconhecem.
Eu já escrevi sobre outras Melhorias no Depurador de Código do VS 2010
(em Inglês) (incluindo fixação de DataTip, Importação/Exportação de
breakpoints, Preservando Variáveis de Último Valor e muito mais). Eu
escreverei mais posts no futuro sobre o novo suporte do VS 2010 para
Intellitrace e Depuração de Arquivos de Dump. Estes recursos fornecem
muitas novas capacidades quem podem tornar a depuração de aplicações
(inclusive aquelas em ambientes de produção) muito mais fácil e mais
poderosa.
Também certifique-se de verificar a Série de Dicas e Truques do Visual Studio 2010
(em Inglês) escrita por Scott Cate para aprender mais sobre como tirar
um melhor proveito do Visual Studio. Ele tem um conjunto de vídeos e
posts gratuitos que são absolutamente impressionantes.
E também verifique a ótima série de posts com Dicas e Truques do Depurador de Código do Visual Studio (em Inglês) escrita por Jim Griesmer. Ele tem um monte de boas dicas e truques que você pode aproveitar.
Espero que ajude,
Scott
PS
Além do blog, eu também estou agora utilizando o Twitter para
atualizações rápidas e para compartilhar links. Siga-me em:
twitter.com/ScottGu
Texto traduzido do post original por
Leniel Macaferi.