A impressão no console / stdout é uma boa estratégia de depuração?

10

Digamos que temos uma função como esta:

public void myStart()
{
    for (int i = 0; i<10; i++) myFunction(i); 
}


private int myFunction(int a)
{

    a = foo(a);
    a = bar(a);
    return a; 
}

private int foo(int a)
{
    //do something here

    //something gnarly here

    //etc
    return aValue;
}

private int bar(int a)
{
    // do something here
    //return aValue;
}

Agora, por qualquer motivo, nosso código não está funcionando. Talvez esteja gerando um erro, talvez esteja retornando o valor errado, talvez tenha ficado preso em um loop infinito.

A primeira coisa que qualquer programador de primeiro ano, é imprimir no console / padrão, (aprendendo a imprimir o Hello World antes de aprender a usar um depurador).

Por exemplo, para depurar esse código, eles podem fazer o seguinte:

private int myFunction(int a)
{
    print("before foo: a=" + a); 
    a = foo(a);
    print("before bar: a=" + a);
    a = bar(a);

    return a; 
}

private int foo(int a)
{
    //do something here
    print ("foo step1: a=" + a); 

    //something gnarly here
    print ("foo step2: a=" + a + " someOtherValue="+ someOtherValue + " array.length= " + someArray.length()); 
    //etc
    return aValue;
}

private int bar(int a)
{
    // do something here
    //return aValue;
}

Agora eles executam o código, obtêm uma grande impressão do console, pela qual podem rastrear onde as coisas estão dando errado.

Uma alternativa, é claro, é definir pontos de interrupção e percorrer o código em cada ponto.

Uma grande vantagem da impressão no console é que o desenvolvedor pode ver o fluxo dos valores de uma só vez, sem precisar clicar nas etapas etc.

Mas a desvantagem é que seu código é repleto de todas essas instruções de impressão que precisam ser removidas.

(É possível, talvez, pedir ao depurador para imprimir apenas determinados valores em um log ?, os pontos de interrupção podem ser facilmente adicionados ou removidos sem modificar o código.)

Eu ainda uso a impressão de console como método primário de depuração, estou me perguntando o quão comum / eficaz isso é em comparação com outra coisa por aí.

Dwjohnston
fonte
11
Você precisa aprender como usar um depurador e usar uma estrutura de log adequada. Isso o deixará muito mais feliz do que imprimir no console (que nem sempre existe).
7
É importante aprender a usar depuradores, no entanto, existem muitas situações em que a depuração printf é o único método de depuração disponível.
whatsisname 23/01

Respostas:

25

As instruções de impressão e o depurador não são mutuamente exclusivos. São apenas ferramentas diferentes disponíveis para você localizar / identificar bugs. Há quem afirme que nunca toca em um depurador e há quem não tem uma única instrução de log / impressão em qualquer lugar do código que escreve. Meu conselho é que você não queira fazer parte de nenhum desses grupos.

Em vez disso, aprenda a usar o log e aprenda a usar um depurador. Com a experiência, você (quase sem precisar pensar nisso) escolhe a ferramenta certa e realiza o trabalho com precisão e eficiência. Sem experiência, às vezes você escolhe um sobre o outro, e talvez demore um pouco mais a vasculhar as variáveis ​​ou vasculhar os arquivos de log, mas isso faz parte do processo de aprendizado.

Então, para responder sua pergunta específica. Sim. Usar impressões para rastrear a execução é uma estratégia de depuração boa e amplamente usada. Contudo...

Em vez de usar instruções de impressão, considere usar uma estrutura de log. As estruturas de log têm um conceito de níveis de log, para que você possa adicionar várias mensagens de log, mas escolha um nível para cada uma. Quando seu aplicativo está sendo executado em condições normais, seu nível seria ERROR ou WARNING, para que apenas informações importantes sejam relatadas. No entanto, ao rastrear o código e precisar entender o fluxo de execução, você pode alterar o logger para INFO ou DEBUG e agora todas as instruções "print" que você já possui no código reportarão informações adicionais.

Usando uma estrutura de log ...

  1. você não precisará excluir todas as impressões depois de terminar.
  2. as impressões deixadas no código, podem ajudar você ou qualquer outro desenvolvedor a depurar esse mesmo código no futuro
  3. você poderá depurar esse código no campo sem precisar reconstruí-lo todas as vezes apenas para adicionar as impressões que você excluiu.
  4. você poderá redirecionar as mensagens de log para onde quiser, não apenas um console. Eles poderiam ir para um arquivo, syslog, DB, socket ... etc

Atualização: Acabei de perceber que, no final, você estava perguntando: "É possível dizer ao depurador para imprimir apenas determinados valores em um log". Dependendo de qual depurador você usa. Muitos depuradores modernos permitem definir uma ação a ser chamada quando um ponto de interrupção é atingido. Em alguns (eu fiz isso no VS e no WinDbg), é possível especificar "imprimir isto e continuar". O Visual Studio os chama de "pontos de rastreamento" em vez de "pontos de interrupção"

DXM
fonte
+1 no primeiro parágrafo. Depuradores e logs resolvem dois problemas muito diferentes.
Blrfl
11
Mas você não concorda que deixar as instruções de log no código piora tudo?
precisa saber é o seguinte
11
depende de que tipo de instruções de log você deixa no local. Acabei de encontrar e removi este: "logger.error (" WHAT ")". Caso contrário, trato o código de log como o resto do meu código. Formate-o, faça com que pareça agradável e informativo. Sim, espalhar uma declaração impressa em todas as outras linhas é um pouco demais e houve momentos em que tive que recorrer a isso. Mas, geralmente, ter de 10 a 20 instruções de log em todo o arquivo (arquivos / classes com tamanho razoável e não gigantescos) não é ruim.
DXM
Recebo que deixando algumas declarações de log in pode ser útil, por exemplo, se você tem um sistema de produção que você pode querer ser registrando diversas variáveis importantes como eles são usados por isso, se algum erro faz surgir você pode ver imediatamente o que aconteceu em sua produção meio Ambiente. No entanto, para o contexto de desenvolvimento , parece confuso. Por exemplo, você está escrevendo sua função de análise e não conseguiu acertar o seu regex - por isso, coloca uma série de instruções de log apenas para verificar o que está acontecendo e, eventualmente, resolver o problema. Eu não acho que ela agrega valor vai para a frente para deixá-los em.
dwjohnston
11
@ Izkata: tudo isso dependeria das especificidades do seu bug específico e da quantidade de registros que o seu código já possui. O ponto que estou tentando entender é que sempre existe o valor de ter instruções de log e tê-las em diferentes níveis: ERR -> WARN ... -> DEBUG. Se você precisar de algo mais específico, certamente comece a adicionar instruções de impressão. Mas minha resposta para alguém que usa "print" como uma declaração de log sempre será alternada para uma estrutura e começará a usá-la.
DXM
3

Registro / impressão e depuradores são técnicas complementares que têm diferentes pontos fortes e fracos - é melhor usar os dois. Mas, no geral, eu diria que os depuradores são a ferramenta superior na maioria dos casos e devem ser usados ​​primeiro, com o registro / impressão usado apenas para as coisas nas quais é realmente melhor.

Vantagens dos depuradores:

  • Você pode inspecionar todo o estado do programa, não apenas os valores que pensou imprimir previamente. Isso pode acelerar enormemente o processo de depuração, reduzindo o ciclo de feedback para menos de um segundo. Especialmente importante quando leva algum tempo para alcançar o bug.
  • Você pode ver de onde vieram as chamadas e até mesmo inspecionar valores no rastreamento da pilha.
  • Você pode (até certo ponto, dependendo do idioma / plataforma) o código de depuração que não pode ser facilmente modificado porque você possui apenas o código binário ou de byte compilado.

Vantagens do registro / impressão:

  • Não requer uma compilação ou configuração especial de depuração. Isso sempre funciona.
  • Pode ser usado para analisar erros que são difíceis de reproduzir e ocorrem raramente
  • Pode ser usado para analisar erros dependentes de tempo, onde a pausa causada por um depurador pode facilmente fazer o erro desaparecer.
  • Fornece informações permanentes que você pode analisar à vontade. Você pode alternar entre a saída em diferentes pontos do fluxo do programa.
Michael Borgwardt
fonte
Outra vantagem do registro é quando você só encontra o problema na décima terceira passagem pelo seu código e realmente pode usar algum traço de como chegou lá. A maioria dos depuradores não possui um botão reverso, mas registrar como os valores com os quais uma função de nível superior foi chamada funcionará e, muitas vezes, pelo menos o aproximará de um pequeno caso reproduzível.
Christopher Creutzig
1

Imprimir de maneira padrão na saída padrão pode ser uma boa estratégia para depurar seu código, por exemplo

  • Eu uso muitas instruções de impressão para ver o que está acontecendo em diferentes níveis do meu código, especialmente se eu não entender completamente o erro

  • ou talvez o erro não tenha nenhuma informação detalhada que possa me indicar qual parte do código exatamente está causando o problema.

No entanto, você precisa se acostumar com as ferramentas de depuração, existem muitas por aí, dependendo do idioma ou plataforma que você usa.

Além disso, outro método é o log, eu registro erros o tempo todo ao trabalhar em aplicativos Android, também com o tratamento de exceções, é possível registrar facilmente um rastreamento de pilha ou uma mensagem de erro da exceção que está sendo gerada.

Plaix
fonte
3
é difícil ler este post (parede de texto). Você se importaria de editá -lo em uma forma melhor?
mosquito
Eu fiz isso um pouco legível. Desculpe pelo anterior!
Plaix 24/01