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?
Respostas:
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
lint
e use uma ferramenta comovalgrind
para capturar problemas comuns relacionados à memória dinâmica.Se você está programando Perl, ligar
strict
ewarnings
e 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.
fonte
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.
fonte
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:
fonte
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.
fonte
Trabalhe com mais cuidado
Este é o software equivalente a "medir duas vezes uma vez":
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.
fonte
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.
fonte
É 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.
fonte
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:
fonte
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.
fonte
O desenvolvimento orientado a teste pode ajudar a reduzir o tempo de depuração:
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.
fonte
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
fonte
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.
fonte
Ó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 ...
fonte
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.
fonte
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.
fonte
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:
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
Um estudo empírico do impacto do PSP em engenheiros individuais (pdf)
Guia de estilo do CPP do Google
Admitindo Derrota em K&R em LCTHW - Zed A. Shaw
Plug-ins IDE - uma maneira de testar a segurança para automatizar a revisão de código | Comunidade de segurança cibernética do TCS
Regras de segurança definidas para código gerenciado
Codificação segura em C ++ 11 e C ++ 14
Visualize a execução do código Java
Visualização SPARQL
WWW2012 Tutorial - Visualizando Consultas SPARQL
fonte