Cheiros de código são um clássico.
Cheira porque provavelmente há muitos casos em que poderia ser editado ou melhorado.
A maioria desses cheiros são apenas indícios de algo que pode estar errado. Eles não são necessariamente consertados per se ... (Você deve investigar isso.)
Código anterior cheira
- Parte I
- parte II
- Parte III
- Parte IV
- Parte V
- Parte VI
- Parte VII
- Parte VIII
- Parte IX
- Parte X
- Parte XI
- Parte XII
- Parte XIII
- Parte XIV
- Parte XV
- Parte XVI
- Parte XVII
- Parte XVIII
- Parte XIX
- Parte XX
Vamos continuar...
Code Smell 101 - Comparação com Booleanos
Ao comparar com booleanos, realizamos conjurações mágicas e obtemos resultados inesperados.
TL;DR: Não compare com o verdadeiro. Ou você é verdadeiro, ou falso ou não deve comparar
problemas
- Elencos ocultos
- A violação do princípio da menor surpresa.
- Violação do princípio Fail Fast
Soluções
- Usar booleanos
- Não misture booleanos com objetos fundidos booleanos
Contexto
Muitos idiomas lançam valores para domínios de cruzamento booleanos.
Código de amostra
Errado
#!/bin/bash if [ false ]; then echo "True" else echo "False" fi # this evaluates to true since # "false" is a non-empty string if [ false ] = true; then echo "True" else echo "False" fi # this also evaluates to true
Certo
#!/bin/bash if false ; then echo "True" else echo "False" fi # this evaluates to false
Detecção
- [x] Automático
Linters podem verificar comparações e avisos explícitos.
Tag
- Castings
Conclusão
É uma prática comum da indústria usar muitos não booleanos como booleanos. Devemos ser muito rigorosos ao usar booleanos.
Relações
Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)
Mais informações
Créditos
Foto de Michael Held no Unsplash
Se não funcionar, não importa o quão rápido não funcione.
-Mich Ravera
Cheiro de Código 102 - Código de Seta
IFs e Elses aninhados são muito difíceis de ler e testar
TL;DR: Evite IFs aninhados. Melhor ainda: evite TODOS os IFs
problemas
- Legibilidade
Soluções
- Extrair método
- Combinar Condições Booleanas
- Remover IFs acidentais
Contexto
No código procedural, é muito comum ver ifs aninhados complexos. Essa solução está mais relacionada a scripts do que a programação orientada a objetos.
Código de amostra
Errado
if (actualIndex < totalItems) { if (product[actualIndex].Name.Contains("arrow")) { do { if (product[actualIndex].price == null) { // handle no price } else { if (!(product[actualIndex].priceIsCurrent())) { // add price } else { if (!hasDiscount) { // handle discount } else { // etc } } } actualIndex++; } while (actualIndex < totalCounf && totalPrice < wallet.money); } else actualIndex++; } return actualIndex; }
Certo
foreach (products as currentProduct) addPriceIfDefined(currentProduct) addPriceIfDefined() { //Several extracts }
Detecção
- [x] Automático
Como muitos linters podem analisar árvores, podemos verificar em tempo de compilação os níveis de aninhamento.
Tag
- Legibilidade
- Complexidade
Conclusão
Seguindo o conselho do tio bob , devemos deixar o código mais limpo do que encontramos.
Refatorar esse problema é fácil.
Relações
Cheiro de código 03 - as funções são muito longas
Cheiro de código 36 - instruções switch/case/elseif/else/if
Mais informações
O propósito da engenharia de software é controlar a complexidade, não criá-la.
- Pâmela Zave See More
Cheiro de Código 103 - Encapsulamento Duplo
Chamar nossos próprios métodos de acesso pode parecer uma boa ideia de encapsulamento. Mas não é.
TL;DR: Não use setters e getters, mesmo para uso privado
problemas
- Setters
- Getters
- Expor atributos privados
Soluções
- Remover configuradores
- Remover getters
- Proteja seus atributos
Contexto
O uso de encapsulamento duplo era um procedimento padrão na década de 90.
Queríamos ocultar detalhes de implementação, mesmo para uso privado.
Isso estava escondendo outro cheiro quando muitas funções dependem da estrutura de dados e da implementação acidental.
Por exemplo, podemos alterar a representação interna de um objeto e confiar em seu protocolo externo.
Custo/benefício não vale a pena.
Código de amostra
Errado
contract MessageContract { string message = "Let's trade"; function getMessage() public constant returns(string) { return message; } function setMessage(string newMessage) public { message = newMessage; } function sendMessage() public constant { this.send(this.getMessage()); // We can access property but make a self call instead } }
Certo
contract MessageContract { string message = "Let's trade"; function sendMessage() public constant { this.send(message); } }
Detecção
- [x] Semiautomático
Podemos inferir getters e setters e verificar se eles são invocados do mesmo objeto.
Tag
- Encapsulamento
Conclusão
O encapsulamento duplo era uma ideia da moda para proteger a implementação acidental, mas expunha mais do que protegia.
Relações
Cheiro de Código 37 - Atributos Protegidos
Mais informações
Créditos
Foto de Ray Hennessy no Unsplash
Encapsule o conceito que varia.
-Erich Gama See More
Cheiro de Código 104 - Afirmar Verdadeiro
Afirmar contra booleanos torna o rastreamento de erros mais difícil.
TL;DR: Não declare verdadeiro a menos que esteja verificando um valor booleano
problemas
- Princípio de falha rápida
Soluções
- Verifique se a condição booleana pode ser melhor reescrita
- Favorecer assertEquals
Contexto
Ao declarar um booleano, nossos mecanismos de teste não podem nos ajudar muito.
Eles apenas nos dizem que algo falhou.
O rastreamento de erros fica mais difícil.
Código de amostra
Errado
<? final class RangeUnitTest extends TestCase { function testValidOffset() { $range = new Range(1, 1); $offset = $range->offset(); $this->assertTrue(10 == $offset); // No functional essential description :( // Accidental description provided by tests is very bad } } // When failing Unit framework will show us // // 1 Test, 1 failed // Failing asserting true matches expected false :( // () <-- no business description :( // // <Click to see difference> - Two booleans // (and a diff comparator will show us two booleans)
Certo
<? final class RangeUnitTest extends TestCase { function testValidOffset() { $range = new Range(1, 1); $offset = $range->offset(); $this->assertEquals(10, $offset, 'All pages must have 10 as offset'); // Expected value should always be first argument // We add a functional essential description // to complement accidental description provided by tests } } // When failing Unit framework will show us // // 1 Test, 1 failed // Failing asserting 0 matches expected 10 // All pages must have 10 as offset <-- business description // // <Click to see difference> // (and a diff comparator will help us and it will be a great help // for complex objects like objects or jsons)
Detecção
- [x] Semiautomático
Alguns linters nos avisam se estamos verificando o booleano após definir essa condição.
Precisamos alterá-lo para uma verificação mais específica.
Tag
- Testar odores
Conclusão
Tente reescrever suas asserções booleanas e você corrigirá as falhas muito mais rapidamente.
Relações
Code Smell 101 - Comparação com Booleanos
Code Smell 07 - Variáveis Booleanas
Mais informações
Créditos
Foto de Joël de Vriend no Unsplash
Finalmente aprendi o que significa 'compatível com versões anteriores'. Isso significa que podemos manter todos os nossos velhos erros.
-Dennie van Tassel
Code Smell 105 - Métodos de comediante
Use nomes profissionais e significativos
TL;DR: Não seja informal ou ofensivo
problemas
- Legibilidade
- Trabalho não profissional
Soluções
- Escolha nomes bons e profissionais.
Contexto
Nossa profissão tem um lado criativo.
Às vezes ficamos entediados e tentamos ser engraçados.
Código de amostra
Errado
function erradicateAndMurderAllCustomers(); // unprofessional and offensive
Certo
function deleteAllCustomers(); // more declarative and professional
Detecção
- [x] Semiautomático
Podemos ter uma lista de palavras proibidas.
Também podemos verificá-los em revisões de código.
Os nomes são contextuais, então seria uma tarefa difícil para um linter automático.
As convenções de nomenclatura devem ser genéricas e não devem incluir jargão cultural.
Tag
- Nomenclatura
Conclusão
Seja profissional na maneira como você nomeia as coisas em seu código.
Não tente ser um comediante dando um nome bobo a uma variável.
Você deve escrever o código de produção para que os futuros desenvolvedores de software (até mesmo você) entendam facilmente.
Relações
Code Smell 38 - Nomes abstratos
Mais informações
Créditos
Foto de Stewart Munro no Unsplash
Essa mentalidade de 'usuários são idiotas e estão confusos com a funcionalidade' do Gnome é uma doença. Se você acha que seus usuários são idiotas, apenas idiotas irão usá-lo.
- Linus Torvalds
Grandes Citações de Engenharia de Software
E isso é tudo por agora…
O próximo artigo explicará mais 5 code smells!