Eu ouvi histórias sobre isso de programadores seniores e já vi algumas delas. Parece que existem mais do que algumas instâncias de programadores escrevendo código inútil. Vou ver coisas como:
- Chamadas de método ou função que não fazem nada de valor.
- Verificações redundantes feitas em um arquivo de classe, objeto ou método separado.
if
declarações que sempre são avaliadas como verdadeiras.- Tópicos que se desdobram e não fazem nada de importante.
Só para citar alguns. Disseram-me que isso ocorre porque os programadores desejam intencionalmente tornar o código confuso para aumentar seu próprio valor para a organização ou garantir negócios repetidos no caso de trabalho contratual ou terceirizado.
Minha pergunta é. Alguém mais viu código assim? Qual foi sua conclusão sobre por que esse código estava lá?
Se alguém escreveu um código como esse, você pode compartilhar o porquê?
coding-style
Ali
fonte
fonte
if (false) {...}
blocos são ótimos para comentar o código! </sarcasm>Respostas:
Ouvi desenvolvedores que tentam fazer com que suas conquistas de codificação soem mais complexas do que realmente são. Nunca ouvi alguém admitir isso, mas vi códigos que atendem aos seus critérios criados intencionalmente por pressa ou práticas inadequadas e não por sabotagem. O código ao redor do código mal-intencionado pode ter sido alterado até o ponto em que uma função específica não é mais útil.
Alguém realmente teria que ver esse código em primeira mão antes de chegar à conclusão de que somente esse desenvolvedor pode gerenciar a complexidade. A maioria dos gerentes e outras pessoas de negócios chega a essa conclusão porque não entende nenhum tipo de código e não deseja refazer a posição.
fonte
Não vi o código como este, mas vi o código que parece inútil ou inútil pelos outros motivos:
Compatibilidade com versões anteriores. Você encontrou uma maneira muito melhor de fazer as coisas, mas deve manter a API / função antiga (e até agora não muito útil) porque algum módulo de terceiros por aí pode estar usando essa API / função para alguma coisa. Mesmo que a função não faça nada de útil, a ausência dela pode quebrar algum código.
Codificação defensiva. Você sabe que as verificações neste código são inúteis porque isso já foi verificado em outro lugar. Mas e se alguém alterar esse código em outro lugar e remover ou alterar as verificações para não corresponder mais às suas condições prévias?
Crescimento orgânico. Em grandes projetos, ao longo dos anos, muitas coisas mudam, e acontece que alguns métodos usados antes não são mais usados, mas ninguém se preocupou em removê-los, pois ninguém controlava se esse método específico era usado ou não, eles apenas refatoravam seus pedaços de código e, por acaso, todos pararam de usar esse método. Ou condições que antes tinham significado, mas a aplicação foi refatorada em outros lugares, para que a condição se tornasse sempre verdadeira, mas ninguém se preocupou em removê-la.
Projeto excessivo. As pessoas podem codificar algumas coisas "apenas no caso de precisarmos" e nunca realmente precisam. Como "vamos criar um tópico, caso tenhamos que fazer algum trabalho offline" e, em seguida, ninguém pede para fazer algo offline, e o programador esquece e passa para outros projetos (ou talvez para outra empresa), e esse código permanece lá para sempre, porque ninguém sabe por que está lá ou se é seguro removê-lo.
Portanto, embora eu nunca tenha visto isso por malícia ou por uma abordagem equivocada da segurança no trabalho, já vi várias vezes isso acontecer como resultado natural do desenvolvimento de software.
fonte
1) sim
2) Nos casos que eu vi, eu colocaria isso de várias maneiras:
Agora talvez eu esteja sendo caridoso com isso, mas minha abordagem geral é que é melhor perdoar / não confrontar essas coisas, do que apontar os dedos e continuar com a má qualidade. Obviamente, as coisas podem ficar ruins o suficiente para que algo tenha que ser feito , mas um leve empurrão na direção certa geralmente é suficiente.
Obviamente, você não pode adotar uma abordagem de laissez-faire se a qualidade / erros impactarem seriamente "os negócios". Mas nessa situação, você precisa de revisões de código obrigatórias e diligentes de tudo, combinadas com um procedimento de teste abrangente.
Na minha experiência, as pessoas tendem a ficar "rígidas" com o código de baixa qualidade (pelo menos em parte), porque isso ofende seus padrões pessoais. É muito bom (pessoalmente) buscar a perfeição, mas não é razoável projetar seus padrões pessoais em outras pessoas. Pelos sons das coisas (por exemplo, pela natureza de seus exemplos), é isso que você está fazendo.
Na IMO, isso não é produtivo e não conduz a um bom relacionamento de trabalho com seus colegas de trabalho.
fonte
Todos esses são sintomas de como o projeto envelhece.
1. Chamadas de método ou função que não fazem nada de valor. Muitas vezes, quando algum código é deixado como está (espero que com um grande aviso preterido , mas como a maioria dos idiomas não tem esse aviso, ele nem sempre é seguido ...) porque, a certa altura, ele serviu a alguns propósito genuíno e ninguém sabia o que poderia acontecer se as linhas ofensivas fossem removidas.
Eu me lembro disso de um dailywtf:
2. Verificações redundantes feitas em um arquivo de classe, objeto ou método separado. As camadas de comunicação também são imperfeitas (leia o Mês do Homem Mítico? Se não, o que você está fazendo no computador !? Vá! LEIA!). Frequentemente, uma pessoa trabalha em algo e sai do projeto, e o próximo, encontrando algum bug bizarro, lança uma verificação extra aqui e ali para tentar eliminá-lo. Quando o bug é removido, as verificações não são porque, bem, se não estiver quebrado, não o conserte.
3. Se declarações que sempre avaliam como verdadeiras. Oh, eu fiz este. Eu recebi um projeto uma vez, ele tinha uma série de provavelmente 10 a 15 blocos if / else . Para mudar o comportamento, basta colocar um
true||
no primeiro bloco. Não foi até meses (anos?) Depois que voltei e disse: "Uau, esse código deveria ter sido destruído, mas nunca foi"4. Tópicos que se desdobram e não fazem nada de especial. Eu posso imaginar uma linha de pensamento assim:
bar
tópico não parece estar fazendo nada, podemos removê-lo?" "Melhor não, já existe há muitos, muitos anos ..."fonte
Sou um pouco mais otimista. Eu acho que o que você descreveu geralmente ocorre quando o código é refatorado descuidadamente.
fonte
Velhos companheiros me contaram uma época em que os consultores eram pagos pelo número de linhas de código que produziam. E, assim, maximizavam os lucros usando construções surpreendentemente longas.
Hoje em dia, eu sempre assumo que o cara ainda está aprendendo o idioma enquanto faz o trabalho. E ele está com pressa.
fonte
A maioria das respostas se resume a esses dois fatos simples:
[1] Código reflete o histórico do código e
[2] Código reflete o futuro esperado do código.
Escrevi funções que não têm valor algum, NO AMBIENTE ATUAL DE APLICAÇÃO, dadas as ESPECIFICAÇÕES ATUAIS, mas podem ser necessárias no futuro.
Escrevi declarações if que, NO PRESENTE, sempre são avaliadas como verdadeiras. Mas talvez no passado pudesse ser falso.
Quanto aos cheques redundantes, ei, eu não confio em outro código, nem confio em meu próprio código. Se um módulo depende de N ser 1 ou 2 ou 3, é muito melhor garantir isso, e falhar informativamente, se não for. É ilegítimo o Módulo B explodir porque o Módulo A estragou tudo; é bastante legítimo que o Módulo B reclame que o Módulo A estragou tudo. E lembre-se de que, no próximo mês, esse parâmetro pode estar vindo do módulo C. ainda não escrito
fonte
Eu já vi isso algumas vezes, na verdade ontem, eu tenho que mesclar alguns dos códigos dos meus chefes no meu novo aplicativo. No caso dele, tudo se resume a uma falta geral de habilidade e entendimento e a crença de que ele pensa que é um desenvolvedor bastante habilidoso.
'Chamadas de método ou função que não fazem nada de valor.' e 'se declarações que sempre avaliam como verdadeiras' são um problema importante com seu código.
fonte
Suspeito que, embora muitos tenham visto um código com esses problemas, poucos se importariam em escrever o mesmo. Com toda a probabilidade, o que você está vendo é uma podridão acumulada de software - alguém adiciona algo, o que realmente não funciona, o próximo mantenedor adiciona código de proteção mais adiante na cadeia para se proteger contra a condição que não foi verificada corretamente no primeiro Lugar, colocar; alguém recebe um relatório de problemas e adiciona ainda mais blindagem a uma instância específica de um problema; outra pessoa adiciona uma verificação mais geral e esquece de remover parte do código antigo adicionado anteriormente, que tratava de sintomas mais específicos etc.
Depois, há o problema da limpeza do código: não há incentivo específico para remover o que parece ser um código morto e um tremendo incentivo para não fazê-lo, porque se você não entender o código completamente, sua avaliação de que o código está "morto" será falho e você acabará quebrando o sistema.
fonte
Não necessariamente ruim. Os métodos em uma classe base geralmente chamam métodos vazios que são considerados pontos de substituição para subclasses. Exemplo: o UIView do Cocoa Touch possui um
-didAddSubview:
método documentado como não fazendo nada na versão padrão. O-addSubview:
método do UIView precisa chamar,-didAddSubview:
mesmo que não faça nada, porque as subclasses podem implementá-lo para fazer alguma coisa. Métodos que não fazem nada e as razões para eles devem ser documentados, é claro.Se uma função / método vazio ou inútil estiver obviamente presente por razões históricas, deve ser excluído. Dê uma olhada nas versões anteriores do código no seu repositório de códigos-fonte, se você não tiver certeza.
Difícil dizer se está tudo bem sem algum contexto. Se as verificações forem claramente feitas pelo mesmo motivo, isso pode significar que não há uma separação clara de responsabilidades e é necessária alguma refatoração, especialmente quando as duas verificações resultam na mesma ação. Se a ação resultante das duas verificações não for a mesma, as duas verificações provavelmente estão sendo realizadas por motivos diferentes, mesmo que a condição seja a mesma, e isso provavelmente está correto.
Há uma grande diferença entre:
e:
onde
foo()
acontece sempre retornartrue
.O primeiro caso acontece muito quando as pessoas estão depurando. É fácil usar um
if (0) {...
para remover temporariamente um pedaço de código enquanto você tenta isolar um bug e depois alterar0
para1
para restaurar esse código. Eleif
deve ser removido assim que você terminar, é claro, mas é fácil esquecer essa etapa ou perder uma ou duas, se você a tiver feito em vários lugares. (É uma boa idéia identificar esses condicionais com um comentário que você possa pesquisar mais tarde.) O único dano é a confusão que isso pode causar no futuro; se o compilador puder determinar o valor da condição em tempo de compilação, ele a removerá completamente.O segundo caso pode ser aceitável. Se a condição representada por
foo()
precisar ser testada em vários locais do código, fatorá-la em uma função ou método separado é geralmente a coisa certa a ser feita, mesmo quefoo()
sempre seja verdadeira agora. Se for concebível quefoo()
possa eventualmente retornarfalse
, isolar essa condição em um método ou função é uma maneira de identificar todos os locais onde o código se baseia nessa condição. No entanto , isso cria algum risco de que afoo() == false
condição não seja testada e possa levar a problemas mais tarde; a solução é garantir que você adicione testes de unidade que testam explicitamente ofalse
caso.Isso soa como um artefato da história e algo que pode ser identificado durante uma revisão de código ou por meio de criação de perfil periódica do software. Suponho que poderia ser criado intencionalmente, mas tenho dificuldade em imaginar que alguém realmente faria isso de propósito.
fonte
Acontece. Muitas vezes, na verdade.
Às vezes, esses becos sem saída de codificação são mais como trilhas antigas de cabras que caíram em ruínas quando uma rodovia mais eficiente / moderna / rápida foi instalada em torno deles.
Em outras ocasiões (e provavelmente sou culpado disso), elas são as bases para a extensão do software quando um conjunto de recursos / funções informado, mas não confirmado, é solicitado. (Às vezes, colocar um pouco de trabalho na compilação inicial, fornecendo alças e similares para trabalhos posteriores que você planeja usar "pode tornar a vida mais fácil, quando isso acontece, ou mais difícil / confusa, se o trabalho posterior não acontecer" evento.)
E muito disso se deve diretamente ao antigo "Se não está quebrado, não encaixe". Às vezes, arrancar o código que você não entende ou que acredita não ser usado pode causar a versão de programação de "The Butterfly Effect". Isso já aconteceu uma ou duas vezes também.
fonte
Às vezes, tenho um booleano global definido como true e, mais tarde, no meu código, um if (bool), durante o tempo de execução, posso definir um ponto de interrupção na instrução if e alternar o booleano para testar alguma coisa.
fonte
Oponho-me a que as
if true
declarações sejam classificadas indiscriminadamente como "código sem sentido".Existe um argumento legítimo para o uso de um
if (1) { ... }
bloco no código C que deseja ser compatível com o padrão C que insistia em que as definições de variáveis estivessem no início de uma função ou apenas queria que as variáveis locais fossem definidas o mais local possível.fonte
if
,while
ou construção semelhante. É improvável que seja muito limpo, mas certamente é permitido de acordo com as especificações do idioma.Um professor meu contou-nos um dia uma história de que um empregador anterior os pagaria com base no número de linhas que eles completaram. Então, eles escreveram várias funções alinhadas com várias dúzias que nunca foram chamadas. Parece um ótimo motivo para escrever código inútil.
fonte
Como o @Andy mencionou, um grande componente que eu vi está quebrando o YAGNI .
Alguém começa com uma suposição sobre o que todos os elementos serão em vez do que muitos elementos podem precisar , o que é uma confusão dos relacionamentos "é um" e "tem um" .
Essa confusão leva a uma estrutura rígida de herança e, em seguida, são métodos que não são implementados porque na verdade nunca são chamados, lógica repetida em que partes precisam ser aprimoradas e fluxos de trabalho geralmente estranhos que não se alinham ao modelo de negócios.
Como muitos outros aqui, eu não vi isso feito com intuito malicioso, mas por falta de conhecimento de um bom design e pela tentativa de fazer com que pareça assim para os outros. Engraçado, parece que os desenvolvedores ainda menos informados parecem se sair melhor nesse sentido, porque pelo menos o código deles não acaba sendo excessivamente projetado ad naseum. ( Princípio KISS )
fonte