Passando muito tempo depurando

24

Ontem, lançamos uma versão v1.0 de um projeto da Web em que passei cerca de 6 semanas trabalhando (ligado e desligado). Eu não fiz nenhum registro exato do meu tempo, mas de acordo com minhas experiências, eu estimaria que, durante todo o tempo que gastei em programação, metade dele foi gasto em depuração. Eu estimo que seja uma boa despesa de depuração de 15 a 20 horas, o que para mim é um tempo precioso que poderia ter sido melhor gasto escrevendo novo código ou finalizando o projeto anteriormente. Também especialmente não ajuda que eu seja um calouro na faculdade em cinco semanas.

O problema é que me sinto mal por passar todo esse tempo depurando. Todo esse tempo gasto na depuração me faz perceber que cometi alguns erros estúpidos enquanto desenvolvia meu projeto, erros que me custaram uma quantidade muito boa de tempo para corrigir.

Como posso impedir que isso aconteça no futuro? Não quero gastar 50% do meu tempo depurando, prefiro gastar 10% depurando e o restante escrevendo um novo código. Quais são algumas das técnicas que posso tentar me ajudar a alcançar esse objetivo?

Ryan
fonte
22
Quando eu era calouro, eu também era um programador lento. Apenas dê 20 anos.
27
sim, boa sorte com isso. "Se a depuração é o processo de remoção de bugs. A programação deve ser o processo de colocá-los." -Edsger Dijkstra
Matt
7
Você aprendeu alguma coisa com esses erros? Se você o fez, não os fará da próxima vez e isso reduzirá o tempo de depuração.
Craig T
5
Isso é chamado de "experiência" e o ajudará em seu próximo projeto.
4
Por falar no final da década de 1940, Maurice Wilkes escreveu: "Assim que começamos a programar, descobrimos, para nossa surpresa, que não era tão fácil acertar os programas como havíamos pensado. A depuração precisava ser descoberta. minhas jornadas entre a sala da EDSAC e o equipamento de perfuração que 'hesitando nos ângulos das escadas' me deram conta com força total de que boa parte do restante da minha vida seria gasta encontrando erros em meus próprios programas ".
Trevor Powell

Respostas:

35

Você está pedindo o Santo Graal da engenharia de software, e ninguém tem "a" resposta para esta pergunta ainda.

O essencial é que você acompanhe os tipos de erros que está cometendo e faça uma análise desses erros para determinar se há uma tendência comum. A análise de causa raiz é o nome formal para esse tipo de introspecção, e há bastante material na web sobre isso.

Os profissionais usam um sistema de rastreamento de bugs para que possam (1) saber o que precisa ser corrigido, mas também (2) analisar o que precisou ser corrigido após o fato. Você não precisa ser tão formal - apenas manter um registro em um caderno pode ser bom para você.

Defeitos do estágio de design

Se você achar que a maioria dos seus erros deriva de um mal-entendido da declaração do problema, ou se continuar descobrindo que escolheu o algoritmo ou o caminho errado a seguir na solução dos seus problemas, você terá problemas no estágio de design.

Convém que você dedique mais tempo no início do projeto e escreva exatamente o que precisa ser feito e como deve ser feito. Revise este trabalho com cuidado, revise o problema original e determine se você realmente está enfrentando o problema da maneira correta. Uma hora ou três horas extras no início pode economizar muitas horas no caminho.

Erros de codificação

Se seu design é sólido, mas você está constantemente lutando com a linguagem com a qual está codificando, obtenha algumas ferramentas que analisarão seu código e o alertarão desde o início e com frequência que você está cometendo erros.

Se você estiver programando em C, ative todos os avisos do compilador, use um verificador semântico como linte use uma ferramenta como valgrindpara capturar problemas comuns relacionados à memória dinâmica.

Se você está programando Perl, ligar stricte warningse atenção o que diz.

Não importa qual idioma você esteja usando, provavelmente existem muitas ferramentas disponíveis para ajudar a detectar erros comuns muito antes de você chegar ao estágio de depuração.

Defeitos do estágio de integração

À medida que você desenvolve seu código seguindo boas práticas de modularidade, é necessário começar a colar as partes separadas. Por exemplo, seções diferentes do seu código podem estar relacionadas à entrada do usuário, interação com o banco de dados, exibição de dados, algoritmos / lógica, e cada uma delas é construída relativamente independente uma da outra (ou seja, você tende a se concentrar na seção em questão em vez de se preocupar com a integração com todo o resto).

Aqui é onde o desenvolvimento orientado a teste (TDD) é muito útil. Cada módulo do seu código pode ter testes que verificam se eles funcionam de acordo com a forma como foram projetados. Esses testes devem ser escritos primeiro ou muito cedo no processo, para que você possa ter um conjunto de "auxiliares" para ser honesto. Quando você começa a fazer tudo funcionar em conjunto e descobre que precisa mudar a maneira como isso ou aquilo é implementado ou interage com outro subsistema, você pode recorrer aos seus testes para garantir que o que fez foi feito. tudo funciona junto não quebra a exatidão do código.

E assim por diante...

Pegue alguns livros sobre engenharia de software e técnicas práticas de codificação, e você aprenderá muitas maneiras diferentes de tornar o desenvolvimento menos caótico e mais confiável. Você também descobrirá que a experiência simples e antiga - obter um diploma da escola de pancadas fortes - também o deixará em forma.

O que quase tudo se resume é que um pouco de tempo e trabalho adiantado compensa em enormes dividendos mais tarde no processo de desenvolvimento / lançamento.

O fato de você ter percebido essas questões tão cedo em sua carreira fala bem para o seu futuro, e desejo-lhe boa sorte.

antitônico
fonte
11
Esta é uma ótima resposta, mas IMHO a uma pergunta ligeiramente diferente. O OP está dizendo que passei 6 semanas on / off escrevendo algo e tive que gastar muito tempo depurando. Ainda não sabemos nada sobre, por exemplo, qualidade, manutenção, escalabilidade de seu produto. Se assumirmos TDD, bom design, rastreamento de erros, ainda há a questão de como escrevemos código (incluindo código de teste que também precisa ser depurado) com menos defeitos. Ativar avisos, usar fiapos etc. são boas sugestões. Mais daqueles da escola de pancadas fortes? :-)
Guy Sirton
11
@ Buy - Sim ... a pergunta do OP era um pouco vaga, por isso fui enfatizar a análise de causa raiz. Você não sabe o que há de errado até saber o que está errado. A razão pela qual eu dei o levantamento das áreas problemáticas é porque eu queria que ele estivesse ciente de muitas armadilhas em potencial e que cada etapa do processo merece seu próprio exame. Pelo que sei, ele pode ser o próximo Tony Hoare, mas um com as habilidades de digitação de um elefante cego - correções diferentes para causas diferentes.
Unpythonic
37

Escrever testes de unidade

Escrever testes de unidade para o seu código forçará você a pensar em sua arquitetura e o incentivará a escrever seu código em pequenas partes testadas com cuidado e controladas. Isso reduzirá bastante seu esforço de depuração, e a pequena quantidade de depuração realizada será limitada a pequenos pedaços de código bem focados.

Além disso, os testes que você escreve "abrangem" seu código; você será capaz de saber quando uma alteração feita no código quebra algo, porque um ou mais de seus testes existentes falharão. Isso reduz a complexidade geral do seu esforço de depuração e aumenta sua confiança de que o código funciona.

O problema, é claro, é que seu tempo gasto na depuração agora é gasto escrevendo testes. Mas você só precisa escrevê-los uma vez, e elas podem ser executadas quantas vezes forem necessárias depois de escrevê-las.

Robert Harvey
fonte
+1 para testes de unidade - quanto mais cedo no processo de desenvolvimento os erros são detectados, mais baratos e fáceis são de corrigir.
Paul R
26

50% para depuração (em um sentido amplo) não é tão ruim assim. As pessoas normalmente gastam muito mais tempo projetando, testando, corrigindo bugs, refatorando e escrevendo testes de unidade do que você escrevendo o código real. Faz parte do trabalho.

E, para ser honesto, é muito pior na programação de manutenção - muitas vezes, eu passava uma hora descobrindo o que exatamente dá errado, depois cinco minutos escrevendo o código para corrigi-lo e meia hora testando tudo. Isso representa pouco mais de 5% de codificação vs. quase 95% de não codificação.

Existem algumas coisas que você pode fazer para reduzir o tempo de depuração:

  • Escreva código depurável . Isso significa: tratamento adequado de erros (com algumas considerações), estruturando seu código para facilitar o acompanhamento, usando declarações, rastreamentos e qualquer outra coisa que possa facilitar a vida do depurador. Evite linhas complicadas; uma linha que faça mais de uma coisa deve ser dividida para que você as percorra individualmente.
  • Escreva código testável . Divida seu código em funções simples (ou qualquer outra coisa que sua linguagem de escolha ofereça suporte); evite efeitos colaterais, pois são difíceis de capturar em testes de unidade. Projete suas funções para que possam ser executadas isoladamente. Evite funções polivalentes. Evite casos extremos. Documente o que suas funções devem fazer.
  • Escreva testes . Ter testes de unidade significa que você sabe que suas funções funcionam para pelo menos um subconjunto de suas entradas; isso também significa que você tem uma verificação de integridade para confirmar que suas alterações não quebram nada. Certifique-se de entender os conceitos de cobertura de código e de entrada, bem como as limitações do teste de unidade.
  • Configure um 'ambiente de trabalho' . Como exatamente você faz isso depende do idioma em questão. Algumas linguagens, como Python ou Haskell, vêm com um intérprete interativo, e você pode carregar o código existente nele para brincar com ele. Isso é perfeito, pois você pode chamar suas funções em qualquer contexto que desejar, com o mínimo de esforço - uma ferramenta inestimável para encontrar e isolar bugs. Outros idiomas não têm esse luxo, e você precisará recorrer a pequenos programas de teste interativos.
  • Escreva código legível . Crie o hábito de escrever seu código para expressar suas intenções da forma mais clara possível. Documente tudo o que não é perfeitamente óbvio.
  • Escreva um código simples . Se o seu próprio cérebro tiver problemas para entender toda a base de código, não é simples e é altamente improvável que alguém seja capaz de entendê-lo completamente. Você não pode depurar o código efetivamente, a menos que entenda o que ele deveria fazer.
  • Seja fácil com o botão 'Excluir' . Qualquer código que você não precisa no momento pertence à lixeira. Se você precisar mais tarde, revive-o do controle de origem (a experiência mostra que isso é extremamente raro). Quanto mais código você dispor, menor será a sua superfície de depuração.
  • Refatorar cedo e frequentemente. Sem refatorar, você não pode manter seu código em um estado depurável enquanto adiciona novos recursos.
tdammers
fonte
11
Além disso, o mundo pode se comportar de maneira diferente do que você espera em caso de problemas. Isso pode causar erros muito sutis.
2
+1. Eu diria que apenas gastar 50% em esforços de depuração é bastante baixo, especialmente mas não apenas em uma base de código estabelecida. Se eu receber um bug, a menos que exija uma reescrita completa das partes relevantes do código (improvável), talvez eu gaste muito mais do que essa fração do tempo total apenas para descobrir o que está errado, testando a correção. A correção em si geralmente é rápida, geralmente representando apenas uma ou algumas linhas de código alterado.
um CVn
@ ThorbjørnRavnAndersen Inferno sim, especialmente em projetos da Web como o OP menciona. Nós estamos tendo um grande tempo com codificação de caracteres esta semana no trabalho ...
Izkata
5

Mais planejamento

É inevitável que você gaste uma boa parte do tempo depurando, 10% é uma meta bastante ambiciosa. Embora uma das melhores maneiras de reduzir o tempo gasto na depuração e no desenvolvimento seja gastar mais tempo na fase de planejamento.

Isso pode variar de diagramas a pseudocódigo em um bloco de planejamento. De qualquer forma, você terá mais tempo para refletir sobre o que seu planejamento cometeu e cometer esses erros durante o desenvolvimento.

Bryan Harrington
fonte
11
+1 porque é isso que faço para reduzir o tempo de depuração. Quando eu iniciar um novo projeto, eu escrever tudo o que eu vou fazer em comentários, e então voltar e substituir os comentários com código
CamelBlues
Faço o mesmo com comentários, mais ainda para me impedir de esquecer de onde parei. Mas eu gosto de desenhar diagramas de classe no papel e suas dependências. Isso me dá uma boa visão do que eu estou pensando naquele momento.
Bryan Harrington
5

Trabalhe com mais cuidado

Este é o software equivalente a "medir duas vezes uma vez":

  • Não codifique se estiver se sentindo distraído ou cansado.
  • Gaste tempo suficiente pensando no problema para ter uma solução limpa e elegante. Soluções simples são menos propensas a ter problemas.
  • Dê toda a sua atenção para a tarefa. Foco.
  • Leia seu código rapidamente após a codificação para tentar procurar erros. Revisão de código próprio.
  • Não espere muito tempo entre a codificação e o teste. O feedback imediato é importante para melhorar.
  • Evite fazer coisas que geralmente levam a erros. Leia sobre cheiros de código .
  • Escolha as ferramentas certas para o trabalho.

Tudo isso dito, nada vai eliminar completamente os defeitos. Você precisa aceitar isso como um fato da vida. Dado este plano de fato para defeitos, por exemplo, teste de unidade. Além disso, não pense que isso significa "demora para sempre" (também conhecido como análise-paralisia). É sobre encontrar o equilíbrio.

Guy Sirton
fonte
4

Outras respostas já cobriram a maior parte do que quero dizer, mas ainda quero dar a você minha opinião (brutalmente honesta) de qualquer maneira:

Basicamente, para um trabalho de software não trivial, espere gastar a grande maioria do seu tempo em manutenção e depuração. Se você estiver trabalhando em um sistema de software de produção maduro e gastando menos de 80 a 90% do seu tempo em manutenção e depuração, estará indo bem!

Agora, obviamente, a distinção entre "manutenção" e "depuração" é um pouco subjetiva. Você considera apenas "bugs" problemas com o código encontrado após o lançamento e os usuários se queixaram deles? Ou é algo que dá errado com seu código depois que você adiciona algo (encontrado em suas próprias fases de teste de pré-lançamento)? Em um sistema de software não trivial (dependendo dos padrões de uso), um pode ser muito maior que o outro. Mas, de qualquer forma, é isso que a programação de qualquer coisa maior do que um programa "Hello world" de brinquedo exige - muita manutenção e depuração. Algumas pessoas dizem até algo como " tudo que se segue à primeira linha de código deve ser" modo de manutenção ",

TL; DR: Parece-me simplesmente que você pode ter uma imagem um pouco irreal do que é a programação de sistemas de software não triviais. A grande maioria do esforço consiste em ajustar, manter, refatorar, corrigir bugs e, em geral, executar tarefas que seriam colocadas em "depuração" (manutenção) - pelo menos em um sentido muito geral - em vez de fazer um trabalho totalmente novo, escrevendo novo código.

Bobby Tables
fonte
2

É difícil fornecer técnicas específicas sem detalhes específicos sobre o que você está fazendo e quais tecnologias está usando. Mas mesmo codificadores realmente bons gastam muito tempo testando e depurando.

Muita coisa é escrever um bom código sem muitos bugs. Você comete erros, depois os corrige, depois se lembra quais foram os erros e o que teve que fazer para corrigi-los e não comete o mesmo erro da próxima vez. E se você ainda não está na faculdade e já está começando a pensar seriamente em maneiras de cometer menos erros, eu diria que você está definitivamente à frente do jogo.

Mason Wheeler
fonte
11
Surpreende-me as pessoas que vejo que não aprendem com seus erros (ou se preocupam em tentar lembrar o que aprenderam). E logo depois que algo explodiu em seu rosto, eles se viram e fazem exatamente a mesma coisa no próximo projeto.
HLGEM
2

INTEGRAÇÃO CONTÍNUA (IC) é a resposta.

Integração Contínua = Sistema de Gerenciamento de Configuração (Git, Mercurial, SVN, etc) + Ferramenta CI + Testes de Unidade + Testes de Fumaça

Essa fórmula deve levá-lo a ler mais sobre Integração Contínua (IC). Abaixo estão alguns recursos nesta área:

karthiks
fonte
1

Realmente, para reduzir a depuração, você pode carregá-la com antecedência planejando com mais profundidade. Ainda não frequentou a faculdade? Eu acho que você verá nas aulas da metade ao fim da faculdade que você cobrirá detalhes do ciclo de vida de desenvolvimento de software que muito bem podem iluminar suas loucuras.

Enquanto tento explicar aos meus empregadores, a melhor maneira de reduzir a manutenção do código e o suporte técnico é gastar o tempo planejando seu código de maneira abrangente com antecedência.

Equipamento
fonte
1

O desenvolvimento orientado a teste pode ajudar a reduzir o tempo de depuração:

  • ter muitos testes pequenos e focados significa que, se alguém falhar, haverá apenas uma pequena quantidade de código que poderia ter causado o problema.
  • trabalhar em pequenas etapas (escrevendo um teste com falha e depois fazendo-o passar) significa que você pode se concentrar em uma tarefa por vez. Ou seja, fazendo o teste atual passar.
  • a refatoração após a aprovação no teste encoraja você a manter seu código claro e compreensível - facilitando o acompanhamento caso ocorram problemas.

Mesmo se você usar o TDD, ainda terá momentos em que precisará usar o depurador. Quando isso acontece, você deve tentar escrever um teste de unidade para reproduzir o cenário que causou a sessão de depuração. Isso garantirá que, se esse problema ocorrer novamente, ele será capturado rapidamente quando o teste falhar, e ele funcionará como um marcador para a área de código que causou o problema - reduzindo a necessidade de depuração.

Jason
fonte
1

A depuração é inevitável na programação, mas a chave aqui é: seu código é fácil de depurar ou não? Se você precisar gastar horas apenas para depurar algo simples, deve haver algo realmente errado com sua arquitetura de código.

Você deve se acostumar a escrever código limpo e remover maus hábitos, como copiar e colar código e escrever métodos longos, etc.

Além disso, você deve refatorar seu código de tempos em tempos. Sugiro que você leia o livro de Martin Fowler: Refatoração: melhorando o design do código existente

Dresden
fonte
1

Outros mencionaram testes e revisão de código. Ambos são extremamente úteis, mas têm uma diferença fundamental - quando é melhor executá-los. É melhor fazer o teste muito próximo da escrita original do código, para que você possa se lembrar com mais facilidade do motivo pelo qual fez as coisas de uma certa maneira e localize o problema mais rapidamente quando ele falha no teste. A revisão de código, por outro lado, é melhor realizada um pouco mais tarde. Você deseja examinar o código sem uma lembrança perfeita, para não encobrir os detalhes nos quais se lembra de ter pensado, mas que não inseriu. Você deseja realizar locais onde seu código não está claro. Você quer o pequeno esforço extra de ter que descobrir o que o código está fazendo. Você deseja aplicar qualquer novo conhecimento adquirido sobre o problema ou interações com outro código ou novas técnicas. Basicamente,

Tudo isso ainda é tangente à sua pergunta. Para gastar menos tempo na depuração, você precisa entender por que teve que depurar em primeiro lugar. Entendendo mal o problema, o conhecimento imperfeito de suas ferramentas e tecnologias e a simples execução de "os dados reais não correspondem aos dados de amostra", todos os tipos de problemas se manifestam de maneiras diferentes e precisam de técnicas e tipos de práticas diferentes para evitar no futuro.

O último ponto que colocarei é a experiência. Não há uma maneira fácil de conseguir isso, você só precisa dedicar tempo. À medida que você ganha experiência, gasta menos tempo na depuração, porque escreverá um código melhor para começar, notará problemas mais cedo e desenvolverá uma melhor intuição sobre qual pode ser a origem do problema. Continue assim e você crescerá constantemente ao longo de sua carreira.

CPhelps
fonte
0

Ótimas respostas acima, mas ninguém mencionou diretamente (embora a maioria tenha sugerido isso):

LER LER LER LER et at nauseam ...

Quanto mais você sabe, menos você não sabe. Um pouco clichê, mas ainda a verdade básica.

Depois de seguir as dicas acima e documentar analiticamente os erros, tente classificá-los e leia a literatura pertinente.

Foi um problema de decisão de design? Leia sobre Design Patterns.

Foi falta de conhecimento da estrutura ou linguagem? Osso sobre isso!

etc

Há duas coisas que um desenvolvedor (ao vivo) nunca pode escapar: change (a única constante em TI) e RTFMing ...

Martin S. Stoller
fonte
0

Testes de unidade e afirmações

Sempre que possível, divida seu código em pequenos pedaços que podem ser testados isoladamente. Isso nem sempre é prático, no entanto. Algumas peças de funcionalidade dependem de entradas extremamente complicadas. Alguns fazem algo que não pode ser facilmente verificado de maneira automatizada, como desenhar coisas na tela. Às vezes, o não-determinismo está envolvido, etc.

Quando você não pode escrever bons testes de unidade, a próxima melhor coisa é afirmar. Enquanto os testes de unidade verificam se você obtém a resposta correta em alguma entrada predeterminada, afirma verificar a sanidade das etapas intermediárias nas entradas do mundo real. Se o seu código tiver erros, ele falhará rapidamente, próximo à raiz do problema e com uma mensagem de erro clara, em vez de longe do problema com uma mensagem de erro ambígua. Além disso, afirma suposições de documentos e torna seu código mais legível.

dsimcha
fonte
0

Quando você inicia um projeto, quantas abordagens alternativas você identifica?

Você tem de duas a quatro abordagens diferentes, com prós e contras para cada uma? Você faz uma seleção fundamentada dentre eles?

Então, o mais importante, você considera a simplicidade tão importante?

O motivo pelo qual pergunto é, na minha experiência, o volume do código e, portanto, o número de bugs (para não mencionar o desempenho), pode variar em mais de uma ordem de magnitude entre uma abordagem de design e outra. O que vejo pessoas altamente experientes fazendo é realizar trabalhos sem mais código do que o necessário.

Eles são totalmente competentes e cientes de todos os algoritmos de estrutura de dados, recursos de linguagens orientadas a objetos e assim por diante, mas seu código parece que não é , porque eles usam essas coisas com moderação ou não, se o problema ocorrer. não requerê-los.

Mike Dunlavey
fonte
0

Toda vez que você corrige um bug, evita cometer o mesmo erro novamente. Para fazer isso, você pode fazer o seguinte:

  • Anote-a em um registro de defeitos , que inclui:

    • tipo de defeito
    • fase em que o defeito foi injetado
    • fase em que foi removido
    • conserte o tempo
    • uma descrição do problema e corrija
  • Adote um guia de estilo para normalizar o estilo do código que você escreve

  • Integre regras de codificação seguras ao seu processo de revisão de código

  • Visualize o fluxo de controle e os dados

Referências

Paul Sweatte
fonte