Como efetivamente depurar código? [fechadas]

33

Os bugs que entram no código podem ser minimizados, mas não totalmente eliminados como está escrito - os programadores são, embora muitos discordem , apenas humanos.

Quando detectamos um erro em nosso código, o que podemos fazer para eliminá-lo? Como devemos abordá-lo para fazer o uso mais eficaz de nosso tempo valioso e nos permitir gastar menos tempo tentando encontrá-lo e mais tempo codificando? Além disso, o que devemos evitar ao depurar?

Observe aqui que não estamos falando sobre prevenção de bugs; nós estamos falando sobre o que fazer quando os erros não aparecem. Este é um campo amplo, eu sei, e pode ser altamente dependente de linguagem, plataforma e ferramentas. Nesse caso, mantenha respostas abrangentes, como mentalidades e métodos gerais.

gablin
fonte
A pergunta vinculada foi removida.
1
Eu acho que a abordagem é realmente simples. Se você o desenvolveu sozinho, sabe tudo sobre ele. Você pode até corrigir o bug sem depurar. Com isso em mente, a melhor maneira é usar seu tempo codificando outra coisa, até que alguém que saiba muito sobre isso possa responder à sua pergunta sobre como corrigi-lo; ou, deixe descansar, codifique outras coisas, até que uma idéia para consertá-lo lhe venha à mente, para que você não perca tempo nem energia. Meu palpite é que sua pergunta é sobre gerenciamento de equipes corporativas.
Poder de Aquário
Eu acho que Raid. Spray pronto para matar insetos. Esta é uma pergunta filosófica? Livros são feitos a partir da mera preponderância ...
ejbytes

Respostas:

38

A mentalidade e a atitude em relação à depuração é talvez a parte mais importante, porque determina com que eficácia você corrigirá o erro e o que aprenderá com ele - se houver.

Clássicos sobre desenvolvimento de software como The Pragmatic Programmer e Code Complete argumentam basicamente pela mesma abordagem: todo erro é uma oportunidade de aprender, quase sempre sobre você (porque apenas os iniciantes culpam o compilador / computador primeiro).

Então, trate-o como um mistério que será interessante desvendar. E desvendar esse mistério deve ser feito sistematicamente, expressando nossas suposições (para nós mesmos ou para outras pessoas) e testando nossas suposições, uma por uma, se necessário - usando todas as ferramentas à nossa disposição, especialmente depuradores e estruturas de teste automatizadas. Depois que o mistério for resolvido, você poderá se sair ainda melhor examinando todo o seu código em busca de erros semelhantes que você possa ter cometido; e escreva um teste automatizado para garantir que o erro não ocorra novamente sem o saber.

Uma última observação - prefiro chamar erros de "erros" e não de "bugs" - Dijkstra censurou seus colegas por usar o último termo porque é desonesto, apoiando a idéia de que fadas perniciosas e inconstantes plantaram bugs em nossos programas enquanto não estávamos ' procurando, em vez de estar lá por causa de nosso próprio pensamento (desleixado): http://www.cs.utexas.edu/users/EWD/transcriptions/EWD10xx/EWD1036.html

Poderíamos, por exemplo, começar com a limpeza de nossa linguagem, não mais chamando um bug de bug, mas chamando de erro. É muito mais honesto, porque coloca a culpa aonde pertence, a saber. com o programador que cometeu o erro. A metáfora animista do bug que apareceu maliciosamente enquanto o programador não estava olhando é intelectualmente desonesta, pois disfarça que o erro é da própria criação do programador. O bom dessa simples mudança de vocabulário é que ela tem um efeito tão profundo: enquanto, antes, um programa com apenas um bug costumava ser "quase correto", depois um programa com um erro é apenas "errado" (porque em erro).

limist
fonte
7
Na verdade, eu gosto do termo "erro" em vez de "bug", não porque atribui a culpa ao "programador que cometeu o erro", mas porque deixa claro que ele pode não ter sido o programador culpado. Para mim, "bug" implica erro no código; enquanto "erro" implica erro em algum lugar . Talvez no código, talvez na configuração do ambiente, talvez nos requisitos. Me deixa maluco quando meu chefe tem uma "lista de erros", na qual metade dos problemas são alterações de requisitos. Chame de lista de tarefas, ferchrissakes!
Carson63000
2
+1 para "todo erro é uma oportunidade para aprender, quase sempre sobre si mesmo (porque apenas iniciantes culpar o compilador / computador primeiro)"
Md Mahbubur Rahman
Você está ciente da história do termo "bug", certo? Quero dizer, como usado no desenvolvimento de software. Obviamente, não temos esse problema hoje, mas um bug realmente atingiu o hardware de um computador despercebido pelo programador e causou um problema. Para que alguém pense em me corrigir, sei que Edison usou esse termo muito antes do incidente da mariposa, e foi por isso que usei a palavra "história", não "origem". Consulte computerworld.com/article/2515435/app-development/… e en.wikipedia.org/wiki/Software_bug#Etymology
threed
@ threed Claro. Mas por algum tempo, os insetos não causaram a grande maioria dos erros de software.
22616
16
  1. Escreva testes. O teste não é apenas excelente na prevenção de bugs (na minha experiência, o TDD feito corretamente elimina quase todos os bugs triviais e estúpidos), mas também ajuda muito na depuração. O teste força seu design a ser bastante modular, o que facilita muito o isolamento e a replicação do problema. Além disso, você controla o ambiente, para que haja muito menos surpresas. Além disso, depois de obter um caso de teste com falha, você pode estar razoavelmente certo de que acertou a verdadeira razão do comportamento que está incomodando.

  2. Aprenda a usar um depurador. printas instruções podem funcionar razoavelmente bem em algum nível, mas um depurador na maioria das vezes é muito útil (e depois que você sabe como usá-las, fica muito mais confortável do que as printinstruções).

  3. Fale sobre alguém sobre o seu problema, mesmo que seja apenas um patinho de borracha . Forçar-se a expressar o problema no qual está trabalhando com palavras realmente faz milagres.

  4. Dê a si mesmo um limite de tempo. Se, por exemplo, depois de 45 minutos você achar que não está indo a lugar algum, basta mudar para outras tarefas por algum tempo. Quando você voltar ao seu bug, esperamos poder ver outras soluções possíveis que você nunca teria considerado antes.

Ryszard Szopa
fonte
2
+1 por "Forçar-se a expressar o problema em que está trabalhando com palavras realmente faz milagres".
precisa saber é o seguinte
E para adicionar a (1), quase todo bug que você vê no código implica que há um bug - ou pelo menos uma omissão - no conjunto de testes. Corrija os dois ao mesmo tempo e, além de provar que resolveu o problema em questão, você estará seguro contra a reintrodução.
Julia Hayward
3

Eu acho que a reprodução de um bug também é importante. Todos os casos que reproduzem o bug podem ser listados e, em seguida, você pode garantir que a correção do bug cubra todos esses casos.

aslisabanci
fonte
3

Há um excelente livro que li sobre esse assunto chamado Por que os programas falham , que descreve várias estratégias para encontrar bugs, desde a aplicação do método científico para isolar e resolver um bug até a depuração delta. A outra parte interessante deste livro é que ele acaba com o termo 'bug'. A abordagem de Zeller é:

(1) Um programador cria um defeito no código. (2) O defeito causa uma infecção (3) A infecção se propaga (4) A infecção causa uma falha.

Se você deseja aprimorar suas habilidades de depuração, recomendo este livro.

Em minha própria experiência pessoal, encontrei muitos bugs em nosso aplicativo, mas o gerenciamento simplesmente nos pressiona para obter novos recursos. Eu sempre ouvi "Nós encontramos esse bug e o cliente ainda não o percebeu, então deixe-o até que o façam". Eu acho que ser reativo em vez de proativo na correção de bugs é uma péssima idéia, pois quando chega a hora de corrigir, você tem outros problemas que precisam ser resolvidos e mais recursos de gerenciamento querem sair o mais rápido possível, para que você seja pego em um ciclo vicioso que pode levar a uma grande quantidade de estresse e esgotamento e, finalmente, a um sistema dominado por defeitos.

A comunicação também é outro fator quando erros são encontrados. Enviar e-mail ou documentá-lo no rastreador de bugs é ótimo, mas na minha própria experiência, outros desenvolvedores encontram um bug semelhante e, em vez de reutilizar a solução que você colocou para corrigir o código (como eles se esqueceram disso) ), eles adicionam suas próprias versões, então você tem 5 soluções diferentes em seu código e, como resultado, parece mais inchado e confuso. Portanto, quando você corrigir um bug, certifique-se de que algumas pessoas revisem a correção e forneçam feedback caso tenham corrigido algo semelhante e encontrem uma boa estratégia para lidar com ela.

limist mencionou o livro The Pragmatic Programmer, que tem algum material interessante sobre a correção de bugs. Usando o exemplo que eu dei no parágrafo anterior, eu veria o seguinte: Software Entrophy , onde a analogia de uma viúva quebrada é usada. Se duas janelas quebradas aparecerem, sua equipe poderá ficar apática por consertá-la, a menos que você tome uma atitude proativa.

Desolate Planet
fonte
Ouvi dizer que "nós encontramos esse bug e o cliente ainda não o percebeu, então deixe-o até que o façam" muitas vezes também. E tendo ido em visitas ao local, muitas vezes o cliente tenha notado, mas não relatou ele. Às vezes, porque pensam que não faz sentido, porque não será consertado, outras porque já estão olhando para a substituição de um concorrente e, outras vezes (com ou sem razão) "bem, é uma pilha de porcaria de qualquer maneira".
Julia Hayward
@JuliaHayward - Esse é frequentemente o caso, mas na sua situação, seus clientes podem estar satisfeitos com a funcionalidade e não se preocuparem muito com o que está acontecendo sob o capô. O problema começa a surgir quando o cliente volta solicitando recursos extras e você precisa adicionar outros aprimoramentos, como tornar seu aplicativo multilíngue, blá blá compatível com dispositivos móveis, começar a olhar o que tem e ver todas as rachaduras na parede.
Desolate Planet
Apenas mostra a você, todos os livros do mundo sobre design de software, testes e boa comunicação e muitos dos produtos em que você trabalha são uma bagunça. Apesar de saber o que é certo, estresse e prazos irrealistas (em face do seu código já bagunçado) são as razões por que o código está no estado em que está. Eu não tenho respostas para isso sozinho, sou bastante distinto no escritório como uma cara de gemidos, enquanto chuto e grito para manter o código saudável e o processo de desenvolvimento suave, mas às vezes a equipe não ' Não se ligam bem.
Desolate Planet
3

Bug, erro, problema, defeito - como você quiser chamá-lo, não faz muita diferença. Vou me ater ao problema, pois é com isso que estou acostumado.

  1. Descobrir qual é a percepção do problema: traduzir de 'Bob ainda não está no sistema' de um cliente para 'Quando tento criar um registro de usuário para Bob, ele falha com uma exceção de chave duplicada, embora Bob ainda não esteja lá'
  2. Descobrir se é realmente um problema ou apenas um mal-entendido (na verdade, Bob não está lá, não há ninguém chamado bob e a inserção deve funcionar).
  3. Tente obter etapas mínimas e confiáveis ​​que você pode seguir para reproduzir o problema - algo como 'Fornecido um sistema com um registro de usuário' Bruce '', quando um registro de usuário 'Bob' é inserido, ocorre uma exceção '
  4. Este é o seu teste - se possível, coloque-o em um equipamento de teste automatizado que você possa executar repetidamente, isso será inestimável durante a depuração. Você também pode fazer parte do seu conjunto de testes para garantir que esse problema específico não reapareça mais tarde.
  5. Tire seu depurador e comece a colocar pontos de interrupção - descubra o caminho do código ao executar o teste e identifique o que está errado. Enquanto você faz isso, também pode refinar seu teste, tornando-o o mais estreito possível - idealmente um teste de unidade.
  6. Corrija-o - verifique se o seu teste foi aprovado.
  7. Verifique se o problema original, conforme descrito pelo cliente, também foi corrigido (muito importante - você pode ter corrigido um subconjunto do problema). Verifique se você não introduziu regressões em outros aspectos do programa.

Se você estiver familiarizado com o código ou se o problema ou a correção for óbvio, poderá pular algumas dessas etapas.

Como devemos abordá-lo para fazer o uso mais eficaz de nosso tempo valioso e nos permitir gastar menos tempo tentando encontrá-lo e mais tempo codificando?

Eu discordo disso, pois implica que escrever um novo código é valioso para se mover do que ter um programa de trabalho de alta qualidade. Não há nada errado em ser o mais eficaz possível na correção de problemas, mas um programa não melhora necessariamente adicionando mais código a ele.

ptyx
fonte
esta é a melhor resposta IMO
marcusshep 28/06
3

Gosto da maioria das outras respostas, mas aqui estão algumas dicas sobre o que fazer antes de fazer qualquer uma dessas perguntas. Irá poupar tempo beaucoup.

  1. Determine se realmente existe um erro. Um bug é SEMPRE uma diferença entre o comportamento e os requisitos do sistema; o testador deve ser capaz de articular o comportamento esperado e real. Se ele não puder fornecer suporte para o comportamento esperado, não há requisitos e não há erros - apenas a opinião de alguém. Mande de volta.

  2. Considere a possibilidade de que o comportamento esperado esteja errado. Isso pode ser devido a uma interpretação incorreta do requisito. Também pode ser devido a um defeito no próprio requisito (um delta entre um requisito detalhado e um requisito de negócios). Você pode enviá-los de volta também.

  3. Isole o problema. Somente a experiência lhe ensinará a maneira mais rápida de fazer isso - algumas pessoas quase conseguem fazê-lo com o estômago. Uma abordagem básica é variar uma coisa, mantendo todas as outras constantes (o problema ocorre em outros ambientes? Com ​​outros navegadores? Em uma região de teste diferente? Em diferentes momentos do dia?). Outra abordagem é observar os despejos de pilha ou mensagens de erro - às vezes você pode dizer apenas pela forma como está formatado qual componente do sistema gerou o erro original (por exemplo, se estiver em alemão, você pode culpar a terceira pessoa com quem trabalha em Berlim).

  4. Se você reduziu para dois sistemas que colaboram, inspecione as mensagens entre os dois sistemas via monitor de tráfego ou arquivos de log e determine qual sistema está se comportando conforme a especificação e qual não é. Se houver mais de dois sistemas no cenário, você poderá executar verificações aos pares e trabalhar "down" na pilha de aplicativos.

  5. A razão pela qual o isolamento do problema é tão crítico é que o problema pode não ser devido a um defeito no código que você controla (por exemplo, sistemas de terceiros ou o ambiente) e você deseja que essa parte assuma o mais rápido possível . Isso serve para poupar o trabalho e colocá-los no ponto imediatamente, para que a resolução possa ser alcançada no menor espaço de tempo possível. Você não deseja trabalhar em um problema por dez dias apenas para descobrir que é realmente um problema com o serviço da web de outra pessoa.

  6. Se você determinou que realmente há um defeito e está realmente no código que você controla, você pode isolar ainda mais o problema procurando o último build "conhecido" bom e inspecionando os logs de controle de origem para alterações que possam ter causado o problema. Isso pode economizar muito tempo.

  7. Se você não conseguir descobrir isso a partir do controle de origem, agora é a hora de anexar seu depurador e percorrer o código para descobrir. As chances são de que você já tenha uma boa idéia do problema.

Depois de saber onde está o erro e pensar em uma correção, eis um bom procedimento para corrigi-lo:

  1. Escreva um teste de unidade que reproduza o problema e falhe.

  2. Sem modificar o teste de unidade, faça-o passar (modificando o código do aplicativo).

  3. Mantenha o teste de unidade em sua suíte de testes para impedir / detectar regressão.

John Wu
fonte
1

Aqui está como eu faço:

  1. use o mesmo método todas as vezes para encontrar o problema. Isso irá melhorar o seu tempo de reação aos erros.
  2. A melhor maneira é provavelmente ler o código. Isso ocorre porque todas as informações estão disponíveis no código. Você só precisa de maneiras eficientes de encontrar a posição correta e a capacidade de entender todos os detalhes.
  3. a depuração é muito lenta e necessária apenas se os programadores ainda não entenderem como o computador executa instruções asm / não conseguem entender as pilhas de chamadas e outras coisas básicas
  4. Tente desenvolver técnicas de prova como o uso de protótipos de função para raciocinar sobre o comportamento do programa. Isso ajudará a encontrar a posição correta mais rapidamente
tp1
fonte
1

Quando detectamos um erro em nosso código, o que podemos fazer para eliminá-lo? Como devemos abordá-lo para fazer o uso mais eficaz de nosso tempo valioso e nos permitir gastar menos tempo tentando encontrá-lo e mais tempo codificando? Além disso, o que devemos evitar ao depurar?

Supondo que você esteja em um ambiente de produção, eis o que você precisa fazer:

  1. Descreva o "erro" corretamente e identifique os eventos que causam a ocorrência.

  2. Determine se o "erro" é um erro de código ou erro de especificação. Por exemplo, inserir um nome de 1 letra pode ser considerado um erro para alguns sistemas, mas um comportamento aceitável para outros sistemas. Às vezes, um usuário relata um erro que acha que é um problema, mas a expectativa do usuário pelo comportamento do sistema não fazia parte dos requisitos.

  3. Se você provou que há um erro e o erro é devido ao código, é possível determinar quais partes do código precisam ser corrigidas para evitar o erro. Examine também o efeito do comportamento nos dados atuais e nas operações futuras do sistema (análise de impacto no código e nos dados).

  4. Nesse ponto, você provavelmente teria uma estimativa de quanto recursos serão consumidos para corrigir o erro. Você pode corrigi-lo imediatamente ou agendar uma correção em uma próxima versão do software. Isso depende também se o usuário final está disposto a pagar pela correção. Você também deve avaliar as diferentes opções disponíveis para corrigir o erro. Pode haver mais de uma maneira. Você precisa selecionar a abordagem que melhor se adequa à situação.

  5. Analise os motivos que fizeram com que esse bug aparecesse (requisitos, codificação, teste etc.). Impor processos que impediriam a condição de ocorrer novamente.

  6. Documente o episódio adequadamente.

  7. Solte a correção (ou a nova versão)

NoChance
fonte