Como superar a programação por coincidência? [fechadas]

24

No livro Programador Pragmático , os escritores mencionam a programação por conceito de coincidência . Explica o que é, por que é causado, quais são os perigos que você pode encontrar e se compara a um campo de minas terrestres em uma guerra.

Você já assistiu velhos filmes de guerra em preto e branco? O soldado cansado avança cautelosamente para fora do mato. Há uma clareira pela frente: existem minas terrestres ou é seguro atravessar? Não há indicações de que seja um campo minado - sem sinais, arame farpado ou crateras. O soldado cutuca o chão à sua frente com sua baioneta e estremecimentos, esperando uma explosão. Não existe um. Então, ele prossegue meticulosamente pelo campo por um tempo, cutucando e cutucando enquanto caminha. Por fim, convencido de que o campo é seguro, ele se endireita e marcha orgulhosamente para a frente, apenas para ser despedaçado.

As sondas iniciais do soldado para minas não revelaram nada, mas isso foi apenas uma sorte. Ele foi levado a uma conclusão falsa - com resultados desastrosos.

Como desenvolvedores, também trabalhamos em campos minados. Há centenas de armadilhas esperando para nos pegar todos os dias. Lembrando a história do soldado, devemos ter cuidado em tirar conclusões falsas. Devemos evitar a programação por coincidência - confiando na sorte e em sucessos acidentais - em favor da programação deliberada ...

Mas não estou realmente satisfeito com a maneira como descrevem o problema "como superá-lo". Sim, você precisa pensar antes de escrever o código, mas como praticar isso? A única coisa que consigo pensar é adicionar recursos aos projetos de código aberto existentes, nos quais você deve ter conhecimento sobre o "o que estou fazendo agora" e o "Como os outros trechos de código estão funcionando", e isso não é aplicável. quando você está escrevendo seus próprios projetos.

EDITAR:

um resumo de suas postagens:

  • Não adivinhe o seu próximo passo, prove que está correto
  • Teste de unidade e refatorar o máximo possível, quando necessário
  • Adicione recursos - compile - teste frequentemente
  • Se você não pode explicar o código para um noob, provavelmente está programando por coincidência.

BTW, é difícil aceitar uma resposta, é realmente difícil. Todas as respostas são realmente ótimas :)

py_script
fonte
6
Ajudaria as pessoas que talvez não leiam o livro há muito tempo a ter um link como pragprog.com/the-pragmatic-programmer/extracts/coincidence .
btilly
A menos que você tenha uma carreira de programação muito curta (ou seja uma loja individual), é provável que você encontre um código que pareça estranhamente familiar e que ande mais tarde, o centavo cai: é seu. Não é apenas uma consideração Open Source ...
Robbie Dee
@Robbie Dee. você pode esclarecer um pouco mais? Eu não entendo você. Na verdade, tenho uma carreira curta em programação e esse é o motivo da tag de programador júnior.
py_script
2
@py_script Eu estava apenas argumentando que você pode facilmente encontrar seu próprio código anos mais tarde (e ficar desconcertado com isso) como o de outra pessoa. Portanto, se você começar com bons hábitos, isso pagará dividendos mais tarde.
Robbie Dee

Respostas:

26

Você não precisa pensar no futuro, apenas seja muito claro sobre o que foi feito e muito claro sobre o que está fazendo agora.

As sub-rotinas devem dizer o que fazem, fazer o que dizem e não ter dependências ocultas. Então, alguém que os chama pode raciocinar mais facilmente sobre o que eles farão.

Evite o estado global. (Variáveis, singletons etc.) Quanto mais você precisar ter em mente para entender o que as coisas fazem, mais difícil será entender o que deve acontecer e encontrar os casos extremos.

Escreva testes de unidade. Os testes de unidade são ótimos para capturar o comportamento real do código que você acabou de escrever, em vez do comportamento ideal que você espera encontrar.

Encurte seu ciclo de edição / compilação / teste. Quando você adiciona um grande pedaço de código e faz um teste ruim, as chances são de que ele se comporte de maneira diferente do que você pensa. Então você o "corrige" com algumas mudanças aleatórias, e você tem a resposta certa no momento, mas não tem idéia de como isso realmente aconteceu. Agora você está programando por coincidência. Mas quando você adiciona 5 linhas e depois testa, as chances de você ter a resposta certa, porque funciona como você pensa que funcionam, são muito melhores. Posso dizer por experiência que 5 blocos de 10 linhas cada, testados individualmente, são um animal muito diferente de 50 linhas de código testadas ao mesmo tempo.

Refatorar impiedosamente. Muitas vezes vi um refator que tornaria meu código um pouco mais simples, mas exigia um monte de trabalho que eu não queria fazer. Depois que comecei a abordar deliberadamente esses refatores como uma prioridade, descobri que geralmente compensa em um mês. Mas observe a chave: os refatores em que me concentro são aqueles que tornam a vida cotidiana mais simples, e não aqueles que atendem a uma estética arbitrária de melhor ou mais geral. Com esses refatores, aprendi a ser muito mais cauteloso.

Nenhuma dessas coisas requer planejamento antecipado. Mas todos facilitam a compreensão do código existente e, portanto, facilitam a implementação do seu próximo pequeno pedaço de maneira deliberada.

btilly
fonte
Obrigado, resposta muito boa. Eu acho que a parte sobre o ciclo é realmente valiosa. Você pode me dar exemplos de refatoração que você deve executá-los, mas levará muito tempo para implementar e isso pode desencorajar alguém?
Python python #
11
Eu tenho muitos exemplos. Em um projeto C ++, criei classes sem métodos de stringificação. Depois que os criei, a depuração ficou mais fácil e o desenvolvimento acelerou. Em um projeto Perl, tínhamos um hash de configuração em que cada desenvolvedor tinha sua própria cópia aprimorada de cada nova configuração. A adição de parâmetros de configuração foi um problema, porque você tinha que editar a configuração de todos os desenvolvedores. Eu escrevi um sistema de template para hashes, e isso ficou mais fácil. Em um sistema de relatórios, adicionei um recurso para mostrar resultados intermediários. Meu desenvolvimento acelerado, e eu ainda tenho um relatório de usuário bug ...
btilly
11
onde o departamento financeiro havia traçado minha lógica e encontrado a consulta exata em que eu errei e qual era o problema. (Eu estava esmagando acidentalmente linhas duplicadas com UNIONonde eu precisava UNION ALL.) E assim por diante.
btilly
11
Dentro de um mês? Normalmente, acho que cada vez que toco no código, sinto que deveria ser refatorado, mas não refatorado, leva quase o tempo necessário para refatorá-lo.
Amy Blankenship
11
@AmyBlankenship Sim. Dentro de um mês. Às vezes ridiculamente por dentro, às vezes não. O arquivo de configuração que mencionei acima é um exemplo de "às vezes não". Demorou alguns dias para eu escrever, documentar e testar um novo mecanismo de modelo. Em seguida, reescreva a configuração existente para usá-la e seja muito mais curta, mas produza a mesma estrutura de dados exata. (Essa foi a parte mais difícil do projeto.) Então ... dias perdidos, com absolutamente nenhum resultado visível. No entanto, o esforço valeu a pena em menos de um mês, mas vem ganhando juros desde então.
btilly
41

Tudo se resume a não adivinhar . Principalmente os novos programadores fazem isso, mas vi veteranos também, porque acham que economiza tempo de pesquisa. Algo não funciona, então você adiciona a +1ou a -1, altera a truepara a falseou vice-versa, reordena algumas instruções, adiciona ou altera atrasos, altera prioridades de threads e outras pequenas transformações, basicamente testando permutações aleatórias até que funcione.

Isso se aplica principalmente à alteração do código existente, mas também é um fator no código totalmente novo, porque ninguém realmente começa do zero. Você está sempre construindo sobre bibliotecas padrão, sistemas operacionais ou pelo menos arquiteturas de processador.

Em outras palavras, você não estará pronto até saber por que sua correção funciona. O caminho a seguir para chegar lá não importa tanto. Às vezes, até permutações aleatórias podem ser úteis para restringir um erro difícil de diagnosticar, desde que você dedique algum tempo para se perguntar: "Ok, alterar verdadeiro para falso corrigiu, mas por quê?"

Karl Bielefeldt
fonte
11
Excelente ponto +1. Em nenhum lugar isso se aplica mais do que correções de código ...
Robbie Dee
Verdade para mim também, infelizmente. Para ser sincero, há dificuldades objetivas, como falta de documentação às vezes. Hoje, eu estava corrigindo um pouco meu código e cheguei ao fato de não saber para que parâmetro é útil, porque havia falta de documentação. Nós apenas sabemos que é um número.
py_script
Eu admito. Ao enfrentar inclinando-se síndrome de palito, ele pode ser mais fácil de empilhar as \ s até que ele funciona que é para descobrir como muitas camadas de escapar você está lutando com ...
btilly
16

O comentário mais assustador que já encontrei em um programa foi

Não toque nisso. Funciona. Não sabemos como ou por quê, mas funciona. 1

e é assustador apenas porque reconhece que o código foi o resultado da programação por coincidência .

Para evitar a programação por coincidência, você deve explicar (a um colega de trabalho, a si mesmo ou a um pato de borracha ) exatamente o que o código faz e por que funciona. Os marcadores para a programação deliberada são principalmente ajuda para avançar em direção ao objetivo de poder explicar o código.


1 Para o contexto, esse comentário apareceu no código que lida com as alternâncias de contexto em um sistema operacional primitivo. O código já estava em produção há vários anos quando o encontrei.

Bart van Ingen Schenau
fonte
2
este é também chamado de voodoo frango codificação c2.com/cgi/wiki?VoodooChickenCoding
minusSeven
11
Mesmo que o codificador acredite que seja verdade, esse tipo de comentário é extremamente inútil. O código pode muito bem ter sido complexo, mas se você ler o código de outra forma, poderá pensar que foi direto. Tudo o que faz é aumentar a paranóia!
Robbie Dee
3
Isso também pode acontecer ao manter uma base de código antiga, em um idioma com o qual a equipe de desenvolvimento atual não se sente muito à vontade.
pcurry
Portanto, o pato de borracha não é apenas para depuração. Bom ... acho que estamos trabalhando na mesma empresa, temos muitos comentários como este: P
py_script
há situações em que uma correção funciona devido a uma falha em uma API e não há uma correção melhor e lógica. A depuração de algumas bibliotecas compiladas de terceiros pode ser tão profunda quanto a depuração do kernel. E mesmo se você encontrou o problema, depois de horas de depuração, há pouco que você pode fazer. Então você aborda o problema de maneira diferente. Você adota o modelo de "caixa preta" que o força a programar por coincidência. Você brinca com o comportamento estranho da caixa preta e, se conseguir fazê-la funcionar da maneira que deseja, ÓTIMO, adicione um comentário com "magia não toque" e siga em frente.
Radu Simionescu
7

Para novos programadores, a parte mais importante de superar isso é realmente entender o que estão fazendo.

Em muitas áreas, quando você não sabe fazer alguma coisa, basta tentar e errar. Tentar algo; se funcionar, ótimo, se não, tente outra coisa.

Na programação, especialmente ao usar uma linguagem que tem o conceito de comportamento indefinido (como C ou C ++), essa abordagem simplesmente não funciona, porque o sucesso não é mais uma decisão booleana. Você pode ter coisas que "meio que" funcionam, que às vezes funcionam, que funcionam para algumas entradas, mas não para outras.

Ocasionalmente, ensinei novos programadores, e a tendência de tentar digitar coisas aleatórias para ver se funciona é comum. Eles digitavam uma linha e depois se viravam para mim e perguntavam: "Funcionaria assim?" embora estivesse claro que eles não tinham absolutamente nenhuma idéia se poderia.

O argumento é que, como um novo programador, você realmente precisa explicar o que seu código faz. Você precisa aprender a ler código, não apenas escrevê-lo.

(É claro que isso também se aplica a programadores experientes, mas minha experiência aqui foi principalmente com novos iniciantes completos.)

Sebastian Redl
fonte
<< Você precisa aprender a ler o código, não apenas escrevê-lo. >> Então, sobre a minha pergunta inicial, você acha que isso me ajudará a adicionar recursos em projetos de código aberto?
py_script
2

É muito fácil codificar, testar e corrigir "na linha de corrida". Você tem alguma funcionalidade que, dada X e Y, produz Z. Mas e se X estiver corrompido e Y não estiver disponível? E se você não conseguir gerar o Z? Sempre tenha em mente o que pode dar errado e faça uma anotação para o ciclo de teste.

Mantenha suas rotinas curtas e descritivas - o melhor código requer poucos (se houver) comentários.

Nomes significativos de métodos, classes e variáveis ​​contribuem bastante para facilitar a legibilidade.

Se você encontrar um cheiro de código, PARE. É pouco provável que esse cheiro desapareça e um pouco de esforço agora pode poupar uma enorme quantidade de sofrimento mais tarde.

Inclua testes no seu processo de desenvolvimento. Eu defenderia o uso do BDD em vez do TDD , pois obriga a descrever o que você pretende alcançar, em vez de confiar cegamente em uma série de testes que podem lhe dar uma falsa sensação de segurança.

Resista ao desejo de adicionar recursos interessantes adicionais (a menos que seja seu próprio projeto de estimação). Qualquer código extra precisa ser projetado, escrito, testado e mantido. Se não for exigido pelo cliente / empresa - você corre o risco de se tornar um grande esgotamento de seus recursos.

Robbie Dee
fonte